AkAudioDevice.cpp 131 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318
  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. AkAudioDevice.cpp: Audiokinetic Audio interface object.
  17. =============================================================================*/
  18. #define AK_ENABLE_ROOMS
  19. #define AK_ENABLE_PORTALS
  20. #include "AkAudioDevice.h"
  21. #include "AkAcousticPortal.h"
  22. #include "AkAudioEvent.h"
  23. #include "AkAudioModule.h"
  24. #include "Wwise/WwiseFileHandlerModule.h"
  25. #include "Wwise/WwiseIOHook.h"
  26. #include "Wwise/WwiseResourceLoader.h"
  27. #include "Wwise/WwiseResourceLoaderImpl.h"
  28. #include "Wwise/API/WAAPI.h"
  29. #include "Wwise/API/WwiseMonitorAPI.h"
  30. #include "Wwise/API/WwiseSoundEngineAPI.h"
  31. #include "Wwise/API/WwiseSpatialAudioAPI.h"
  32. #include "Wwise/API/WwiseStreamMgrAPI.h"
  33. #include "Wwise/Stats/Global.h"
  34. #include "WwiseInitBankLoader/WwiseInitBankLoader.h"
  35. #include "AkCallbackInfoPool.h"
  36. #include "AkComponent.h"
  37. #include "AkComponentCallbackManager.h"
  38. #include "AkComponentHelpers.h"
  39. #include "AkGameObject.h"
  40. #include "AkLateReverbComponent.h"
  41. #include "AkRoomComponent.h"
  42. #include "AkRtpc.h"
  43. #include "AkSettings.h"
  44. #include "AkSpotReflector.h"
  45. #include "AkStateValue.h"
  46. #include "AkSwitchValue.h"
  47. #include "AkTrigger.h"
  48. #include "WwiseUnrealDefines.h"
  49. #include "AkWaapiClient.h"
  50. #include "AkWaapiUtils.h"
  51. #include "EngineUtils.h"
  52. #include "Async/Async.h"
  53. #include "Async/TaskGraphInterfaces.h"
  54. #include "Camera/PlayerCameraManager.h"
  55. #include "Components/BrushComponent.h"
  56. #include "Engine/GameEngine.h"
  57. #include "GameFramework/PlayerController.h"
  58. #include "GameFramework/WorldSettings.h"
  59. #include "InitializationSettings/AkInitializationSettings.h"
  60. #include "Internationalization/Culture.h"
  61. #include "Internationalization/Internationalization.h"
  62. #include "Misc/App.h"
  63. #include "Misc/ScopeLock.h"
  64. #include "Runtime/Launch/Resources/Version.h"
  65. #include "UObject/Object.h"
  66. #include "UObject/UObjectGlobals.h"
  67. #include "UObject/UObjectIterator.h"
  68. #include "Wwise/WwiseExternalSourceManager.h"
  69. #if WITH_EDITOR
  70. #include "Editor.h"
  71. #include "EditorSupportDelegates.h"
  72. #include "LevelEditor.h"
  73. #include "SEditorViewport.h"
  74. #include "UnrealEdMisc.h"
  75. #ifndef AK_OPTIMIZED
  76. #include "AkSettingsPerUser.h"
  77. #endif
  78. #endif
  79. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  80. #include "Wwise/WwiseProjectDatabase.h"
  81. #endif
  82. #include <inttypes.h>
  83. /*------------------------------------------------------------------------------------
  84. Statics and Globals
  85. ------------------------------------------------------------------------------------*/
  86. bool FAkAudioDevice::m_bSoundEngineInitialized = false;
  87. bool FAkAudioDevice::m_EngineExiting = false;
  88. TMap<uint32, TArray<uint32>> FAkAudioDevice::EventToPlayingIDMap;
  89. TMap<uint32, EAkAudioContext> FAkAudioDevice::PlayingIDToAudioContextMap;
  90. TMap<uint32, FOnSwitchValueLoaded> FAkAudioDevice::OnSwitchValueLoadedMap;
  91. TArray<TWeakObjectPtr<UAkAudioType>> FAkAudioDevice::AudioObjectsToLoadAfterInitialization;
  92. FCriticalSection FAkAudioDevice::EventToPlayingIDMapCriticalSection;
  93. /*------------------------------------------------------------------------------------
  94. Defines
  95. ------------------------------------------------------------------------------------*/
  96. static constexpr auto InvariantLCID = 0x7F;
  97. /*------------------------------------------------------------------------------------
  98. Helpers
  99. ------------------------------------------------------------------------------------*/
  100. namespace FAkAudioDevice_Helpers
  101. {
  102. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  103. static TMap<AkGameObjectID, FName> ComponentNameMap;
  104. #endif
  105. AKRESULT RegisterGameObject(AkGameObjectID in_gameObjId, const FString& Name)
  106. {
  107. AKRESULT Result;
  108. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  109. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  110. #ifdef AK_OPTIMIZED
  111. Result = SoundEngine->RegisterGameObj(in_gameObjId);
  112. #else
  113. if (Name.Len() > 0)
  114. {
  115. Result = SoundEngine->RegisterGameObj(in_gameObjId, TCHAR_TO_ANSI(*Name));
  116. }
  117. else
  118. {
  119. Result = SoundEngine->RegisterGameObj(in_gameObjId);
  120. }
  121. #endif
  122. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  123. if (Result == AK_Success)
  124. {
  125. ComponentNameMap.Add(in_gameObjId, FName(Name));
  126. }
  127. #endif
  128. UE_CLOG(LIKELY(Result == AK_Success), LogAkAudio, VeryVerbose, TEXT("Registered Object ID %" PRIu64 " (%s)"), in_gameObjId, *Name);
  129. UE_CLOG(UNLIKELY(Result != AK_Success), LogAkAudio, Warning, TEXT("Error registering Object ID %" PRIu64 " (%s): (%" PRIu32 ") %s"), in_gameObjId, *Name, Result, WwiseUnrealHelper::GetResultString(Result));
  130. return Result;
  131. }
  132. typedef TMap<AkGlobalCallbackLocation, FAkAudioDeviceDelegates::FOnAkGlobalCallback> FDelegateLocationMap;
  133. FDelegateLocationMap DelegateLocationMap;
  134. void GlobalCallback(AK::IAkGlobalPluginContext* Context, AkGlobalCallbackLocation Location, void* Cookie)
  135. {
  136. const FAkAudioDeviceDelegates::FOnAkGlobalCallback* Delegate = DelegateLocationMap.Find(Location);
  137. if (Delegate && Delegate->IsBound())
  138. {
  139. Delegate->Broadcast(Context, Location);
  140. }
  141. }
  142. void UnregisterGlobalCallbackDelegate(FAkAudioDeviceDelegates::FOnAkGlobalCallback* Delegate, FDelegateHandle Handle, AkGlobalCallbackLocation Location)
  143. {
  144. if (!Delegate)
  145. return;
  146. Delegate->Remove(Handle);
  147. if (Delegate->IsBound())
  148. return;
  149. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  150. if (UNLIKELY(!SoundEngine)) return;
  151. SoundEngine->UnregisterGlobalCallback(GlobalCallback, Location);
  152. }
  153. void UnregisterAllGlobalCallbacks()
  154. {
  155. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  156. if (LIKELY(SoundEngine))
  157. {
  158. for (auto DelegateLocationPair : FAkAudioDevice_Helpers::DelegateLocationMap)
  159. {
  160. auto Location = DelegateLocationPair.Key;
  161. SoundEngine->UnregisterGlobalCallback(GlobalCallback, Location);
  162. }
  163. }
  164. FAkAudioDevice_Helpers::DelegateLocationMap.Empty();
  165. }
  166. }
  167. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  168. static bool GetInfoErrorMessageTranslatorFunction(IWwiseSoundEngineAPI::TagInformationBridge::Type* in_pTagList, AkUInt32 in_uCount, AkUInt32& out_uTranslated)
  169. {
  170. FString Name;
  171. FWwiseDataStructureScopeLock DB(*FWwiseProjectDatabase::Get());
  172. for (AkUInt32 i = 0; i < in_uCount && out_uTranslated != in_uCount; i++)
  173. {
  174. auto& Tag = in_pTagList[i];
  175. if (Tag.m_infoIsParsed)
  176. continue;
  177. const AkUInt32 ID = FPlatformMemory::ReadUnaligned<AkUInt32>((AkUInt8*)Tag.m_args);
  178. const auto AssetInfo = FWwiseObjectInfo(ID);
  179. switch (*Tag.m_pTag)
  180. {
  181. case 'b': //Bank ID
  182. {
  183. const auto RefBank = DB.GetSoundBank(AssetInfo);
  184. if (LIKELY(RefBank.IsValid()))
  185. {
  186. Name = RefBank.SoundBankShortName().ToString();
  187. }
  188. break;
  189. }
  190. case 'g': //The only tag in 64 bits
  191. {
  192. const AkUInt64 GoId = FPlatformMemory::ReadUnaligned<AkUInt64>((AkUInt8*)Tag.m_args);
  193. const auto* NamePtr = FAkAudioDevice_Helpers::ComponentNameMap.Find(GoId);
  194. if (LIKELY(NamePtr))
  195. {
  196. Name = NamePtr->ToString();
  197. }
  198. break;
  199. }
  200. case 'm': //Media ID
  201. {
  202. const auto RefMedia = DB.GetMediaFile(AssetInfo);
  203. if (LIKELY(RefMedia.IsValid()))
  204. {
  205. Name = RefMedia.MediaShortName().ToString();
  206. }
  207. break;
  208. }
  209. case 'p': //Plugin
  210. {
  211. const auto RefPlugin = DB.GetCustomPlugin(AssetInfo);
  212. if (LIKELY(RefPlugin.IsValid()))
  213. {
  214. Name = RefPlugin.CustomPluginName().ToString();
  215. }
  216. break;
  217. }
  218. case 's': //SwitchStates ID
  219. {
  220. const auto RefSwitchGroup = DB.GetSwitchGroup(AssetInfo);
  221. if (RefSwitchGroup.IsValid())
  222. {
  223. Name = RefSwitchGroup.SwitchGroupName().ToString();
  224. break;
  225. }
  226. const auto RefStateGroup = DB.GetStateGroup(AssetInfo);
  227. if (RefStateGroup.IsValid())
  228. {
  229. Name = RefStateGroup.StateGroupName().ToString();
  230. }
  231. break;
  232. }
  233. case 'w': //WwiseObject ID
  234. {
  235. //$w is generic, it can mean a lot of unrelated types.
  236. const TCHAR* FoundType = TEXT("");
  237. FString FoundName;
  238. const auto EventInfo = FWwiseEventInfo(ID);
  239. const auto RefEvents = DB.GetEvent(EventInfo);
  240. if (RefEvents.Num() > 0)
  241. {
  242. FoundType = TEXT("Event");
  243. FoundName = RefEvents.Array()[0].EventName().ToString();
  244. }
  245. const auto RefGameParameter = DB.GetGameParameter(AssetInfo);
  246. if (RefGameParameter.IsValid())
  247. {
  248. const auto NewName = RefGameParameter.GameParameterName().ToString();
  249. if (UNLIKELY(!FoundName.IsEmpty() && NewName != FoundName))
  250. {
  251. UE_LOG(LogAkAudio, Warning, TEXT("Found two different names for the same object ID %" PRIu32 ": %s %s and GameParameter %s. Ignoring."), FoundType, *FoundName, *NewName);
  252. continue;
  253. }
  254. FoundType = TEXT("GameParameter");
  255. FoundName = NewName;
  256. }
  257. const auto RefShareSet = DB.GetPluginShareSet(AssetInfo);
  258. if (RefShareSet.IsValid())
  259. {
  260. const auto NewName = RefShareSet.PluginShareSetName().ToString();
  261. if (UNLIKELY(!FoundName.IsEmpty() && NewName != FoundName))
  262. {
  263. UE_LOG(LogAkAudio, Warning, TEXT("Found two different names for the same object ID %" PRIu32 ": %s %s and ShareSet %s. Ignoring."), FoundType, *FoundName, *NewName);
  264. continue;
  265. }
  266. FoundType = TEXT("ShareSet");
  267. FoundName = NewName;
  268. }
  269. const auto RefBus = DB.GetBus(AssetInfo);
  270. if (RefBus.IsValid())
  271. {
  272. const auto NewName = RefBus.BusName().ToString();
  273. if (UNLIKELY(!FoundName.IsEmpty() && NewName != FoundName))
  274. {
  275. UE_LOG(LogAkAudio, Warning, TEXT("Found two different names for the same object ID %" PRIu32 ": %s %s and Bus %s. Ignoring."), FoundType, *FoundName, *NewName);
  276. continue;
  277. }
  278. FoundType = TEXT("Bus");
  279. FoundName = NewName;
  280. }
  281. const auto RefAuxBus = DB.GetAuxBus(AssetInfo);
  282. if (RefAuxBus.IsValid())
  283. {
  284. const auto NewName = RefAuxBus.AuxBusName().ToString();
  285. if (UNLIKELY(!FoundName.IsEmpty() && NewName != FoundName))
  286. {
  287. UE_LOG(LogAkAudio, Warning, TEXT("Found two different names for the same object ID %" PRIu32 ": %s %s and AuxBus %s. Ignoring."), FoundType, *FoundName, *NewName);
  288. continue;
  289. }
  290. FoundType = TEXT("AuxBus");
  291. FoundName = NewName;
  292. }
  293. // Can be other things, such as Sound.
  294. if (!FoundName.IsEmpty())
  295. {
  296. Name = FoundName;
  297. break;
  298. }
  299. else
  300. {
  301. continue;
  302. }
  303. }
  304. default:
  305. continue; //Not supported, ignore.
  306. }
  307. if (!Name.IsEmpty())
  308. {
  309. AKPLATFORM::SafeStrCpy(Tag.m_parsedInfo, TCHAR_TO_AK(*Name), AK_TRANSLATOR_MAX_NAME_SIZE);
  310. Tag.m_len = Name.Len();
  311. Tag.m_infoIsParsed = true;
  312. out_uTranslated++;
  313. }
  314. }
  315. return out_uTranslated == in_uCount;
  316. }
  317. #endif
  318. /*------------------------------------------------------------------------------------
  319. Implementation
  320. ------------------------------------------------------------------------------------*/
  321. FDelegateHandle FAkAudioDevice::RegisterGlobalCallback(FAkAudioDeviceDelegates::FOnAkGlobalCallback::FDelegate Callback, AkGlobalCallbackLocation Location)
  322. {
  323. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  324. if (UNLIKELY(!SoundEngine)) return {};
  325. auto& Delegate = FAkAudioDevice_Helpers::DelegateLocationMap.FindOrAdd(Location);
  326. FDelegateHandle Handle = Delegate.Add(Callback);
  327. auto result = SoundEngine->RegisterGlobalCallback(FAkAudioDevice_Helpers::GlobalCallback, Location);
  328. if (result != AK_Success)
  329. {
  330. FAkAudioDevice_Helpers::UnregisterGlobalCallbackDelegate(&Delegate, Handle, Location);
  331. Handle.Reset();
  332. }
  333. return Handle;
  334. }
  335. void FAkAudioDevice::UnregisterGlobalCallback(FDelegateHandle Handle, AkGlobalCallbackLocation Location)
  336. {
  337. const auto& Delegate = FAkAudioDevice_Helpers::DelegateLocationMap.Find(Location);
  338. FAkAudioDevice_Helpers::UnregisterGlobalCallbackDelegate(Delegate, Handle, Location);
  339. }
  340. AKRESULT FAkAudioDevice::RegisterOutputDeviceMeteringCallback(AkOutputDeviceID OutputID,
  341. AkOutputDeviceMeteringCallbackFunc Callback,
  342. AkMeteringFlags MeteringFlags,
  343. void* Cookie)
  344. {
  345. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  346. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  347. return SoundEngine->RegisterOutputDeviceMeteringCallback(OutputID, Callback, MeteringFlags, Cookie);
  348. }
  349. AKRESULT FAkAudioDevice::UnregisterOutputDeviceMeteringCallback(AkOutputDeviceID OutputID)
  350. {
  351. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  352. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  353. return SoundEngine->RegisterOutputDeviceMeteringCallback(OutputID, nullptr, AK_NoMetering, nullptr);
  354. }
  355. #if WITH_EDITORONLY_DATA
  356. UAkComponent* FAkAudioDevice::CreateListener(UWorld* World, FEditorViewportClient* ViewportClient)
  357. {
  358. if (!IsRunningGame())
  359. {
  360. FString ComponentName = TEXT("AkListener_") + World->GetName();
  361. if (ViewportClient)
  362. {
  363. ComponentName = TEXT("AkListener_") + FString::FromInt(ViewportClient->ViewIndex) + World->GetName();
  364. }
  365. UAkComponent* Listener = NewObject<UAkComponent>(World->GetWorldSettings(), FName(*ComponentName), RF_Transient);
  366. if (Listener != nullptr)
  367. {
  368. Listener->MarkAsEditorOnlySubobject();
  369. Listener->RegisterComponentWithWorld(World);
  370. AddDefaultListener(Listener);
  371. }
  372. return Listener;
  373. }
  374. else
  375. {
  376. return nullptr;
  377. }
  378. }
  379. FTransform FAkAudioDevice::GetEditorListenerPosition(int32 ViewIndex) const
  380. {
  381. if (ViewIndex < ListenerTransforms.Num())
  382. {
  383. return ListenerTransforms[ViewIndex];
  384. }
  385. return FTransform();
  386. }
  387. #endif
  388. bool FAkAudioDevice::ShouldNotifySoundEngine(EWorldType::Type WorldType) { return WorldType == EWorldType::PIE || WorldType == EWorldType::Game; }
  389. void FAkAudioDevice::LoadAudioObjectsAfterInitialization(TWeakObjectPtr<UAkAudioType>&& InAudioType)
  390. {
  391. AudioObjectsToLoadAfterInitialization.Add(InAudioType);
  392. }
  393. void FAkAudioDevice::LoadDelayedObjects()
  394. {
  395. if (AudioObjectsToLoadAfterInitialization.Num() > 0)
  396. {
  397. SCOPED_AKAUDIO_EVENT_F_3(TEXT("LoadDelayedObjects: Loading %d Object%s"), (int)AudioObjectsToLoadAfterInitialization.Num(), AudioObjectsToLoadAfterInitialization.Num() > 1 ? TEXT("s") : TEXT(""));
  398. UE_LOG(LogAkAudio, Log, TEXT("FAkAudioDevice::LoadDelayedObjects: Loading %d delayed Wwise Object%s after initialization."), AudioObjectsToLoadAfterInitialization.Num(), AudioObjectsToLoadAfterInitialization.Num() > 1 ? TEXT("s") : TEXT(""));
  399. for (auto& WeakAudioType : AudioObjectsToLoadAfterInitialization)
  400. {
  401. auto* AudioType = WeakAudioType.Get();
  402. if (LIKELY(AudioType))
  403. {
  404. AudioType->LoadData();
  405. }
  406. }
  407. AudioObjectsToLoadAfterInitialization.Empty();
  408. }
  409. }
  410. namespace FAkAudioDevice_WaapiHelper
  411. {
  412. void Subscribe(FAkWaapiClient* waapiClient, uint64& subscriptionId, const char* uri, const TSharedRef<FJsonObject>& options, WampEventCallback callback)
  413. {
  414. if (subscriptionId == 0)
  415. {
  416. TSharedPtr<FJsonObject> result;
  417. waapiClient->Subscribe(uri, options, callback, subscriptionId, result);
  418. }
  419. }
  420. void RemoveCallback(FAkWaapiClient* waapiClient, uint64& subscriptionId)
  421. {
  422. if (subscriptionId > 0)
  423. {
  424. waapiClient->RemoveWampEventCallback(subscriptionId);
  425. subscriptionId = 0;
  426. }
  427. }
  428. void Unsubscribe(FAkWaapiClient* waapiClient, uint64& subscriptionId)
  429. {
  430. if (subscriptionId > 0)
  431. {
  432. TSharedPtr<FJsonObject> result;
  433. waapiClient->Unsubscribe(subscriptionId, result);
  434. RemoveCallback(waapiClient, subscriptionId);
  435. }
  436. }
  437. }
  438. /**
  439. * Initializes the audio device and creates sources.
  440. *
  441. * @return true if initialization was successful, false otherwise
  442. */
  443. bool FAkAudioDevice::Init()
  444. {
  445. SCOPED_AKAUDIO_EVENT_2(TEXT("FAkAudioDevice::Init"));
  446. #if UE_SERVER
  447. return false;
  448. #endif
  449. if (!EnsureInitialized()) // ensure audiolib is initialized
  450. {
  451. UE_LOG(LogAkAudio, Log, TEXT("Audiokinetic Audio Device initialization failed."));
  452. return false;
  453. }
  454. #if !WITH_EDITOR
  455. if (auto* akSettings = GetDefault<UAkSettings>())
  456. {
  457. for (auto& entry : akSettings->UnrealCultureToWwiseCulture)
  458. {
  459. auto culturePtr = FInternationalization::Get().GetCulture(entry.Key);
  460. if (culturePtr && culturePtr->GetLCID() != InvariantLCID)
  461. {
  462. CachedUnrealToWwiseCulture.Add(culturePtr, entry.Value);
  463. }
  464. }
  465. }
  466. #endif
  467. #if AK_SUPPORT_WAAPI
  468. if (auto waapiClient = FAkWaapiClient::Get())
  469. {
  470. ProjectLoadedHandle = waapiClient->OnProjectLoaded.AddLambda([this, waapiClient]
  471. {
  472. if (!waapiClient->IsConnected())
  473. return;
  474. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  475. options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>> { MakeShareable(new FJsonValueString(WwiseWaapiHelper::PARENT)) });
  476. auto wampEventCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> in_UEJsonObject)
  477. {
  478. AsyncTask(ENamedThreads::GameThread, [this]
  479. {
  480. #if WITH_EDITOR
  481. FEditorSupportDelegates::RedrawAllViewports.Broadcast();
  482. #endif
  483. OnWwiseProjectModification.Broadcast();
  484. });
  485. });
  486. FAkAudioDevice_WaapiHelper::Subscribe(waapiClient, WaapiSubscriptionIds.Renamed, ak::wwise::core::object::nameChanged, options, wampEventCallback);
  487. FAkAudioDevice_WaapiHelper::Subscribe(waapiClient, WaapiSubscriptionIds.PreDeleted, ak::wwise::core::object::preDeleted, options, wampEventCallback);
  488. FAkAudioDevice_WaapiHelper::Subscribe(waapiClient, WaapiSubscriptionIds.ChildRemoved, ak::wwise::core::object::childRemoved, options, wampEventCallback);
  489. FAkAudioDevice_WaapiHelper::Subscribe(waapiClient, WaapiSubscriptionIds.ChildAdded, ak::wwise::core::object::childAdded, options, wampEventCallback);
  490. FAkAudioDevice_WaapiHelper::Subscribe(waapiClient, WaapiSubscriptionIds.Created, ak::wwise::core::object::created, options, wampEventCallback);
  491. });
  492. ConnectionLostHandle = waapiClient->OnConnectionLost.AddLambda([this, waapiClient]
  493. {
  494. if (!waapiClient->IsConnected())
  495. return;
  496. FAkAudioDevice_WaapiHelper::RemoveCallback(waapiClient, WaapiSubscriptionIds.Renamed);
  497. FAkAudioDevice_WaapiHelper::RemoveCallback(waapiClient, WaapiSubscriptionIds.PreDeleted);
  498. FAkAudioDevice_WaapiHelper::RemoveCallback(waapiClient, WaapiSubscriptionIds.ChildRemoved);
  499. FAkAudioDevice_WaapiHelper::RemoveCallback(waapiClient, WaapiSubscriptionIds.ChildAdded);
  500. FAkAudioDevice_WaapiHelper::RemoveCallback(waapiClient, WaapiSubscriptionIds.Created);
  501. });
  502. ClientBeginDestroyHandle = waapiClient->OnClientBeginDestroy.AddLambda([this, waapiClient]
  503. {
  504. if (ProjectLoadedHandle.IsValid())
  505. {
  506. waapiClient->OnProjectLoaded.Remove(ProjectLoadedHandle);
  507. ProjectLoadedHandle.Reset();
  508. }
  509. if (ConnectionLostHandle.IsValid())
  510. {
  511. waapiClient->OnConnectionLost.Remove(ConnectionLostHandle);
  512. ConnectionLostHandle.Reset();
  513. }
  514. });
  515. }
  516. #endif // AK_SUPPORT_WAAPI
  517. FWorldDelegates::OnPreWorldInitialization.AddLambda(
  518. [&](UWorld* World, const UWorld::InitializationValues IVS)
  519. {
  520. WorldVolumesUpdatedMap.Add(World, false);
  521. }
  522. );
  523. FWorldDelegates::OnPostWorldInitialization.AddLambda(
  524. [&](UWorld* World, const UWorld::InitializationValues IVS)
  525. {
  526. World->AddOnActorSpawnedHandler(FOnActorSpawned::FDelegate::CreateRaw(this, &FAkAudioDevice::OnActorSpawned));
  527. }
  528. );
  529. FWorldDelegates::OnWorldCleanup.AddLambda(
  530. [this](UWorld* World, bool bSessionEnded, bool bCleanupResources)
  531. {
  532. CleanupComponentMapsForWorld(World);
  533. if (WorldVolumesUpdatedMap.Contains(World))
  534. WorldVolumesUpdatedMap.Remove(World);
  535. }
  536. );
  537. FWorldDelegates::OnWorldPostActorTick.AddLambda(
  538. [&](UWorld* World, ELevelTick TickType, float DeltaSeconds)
  539. {
  540. if (WorldVolumesUpdatedMap.Contains(World))
  541. WorldVolumesUpdatedMap[World] = false;
  542. else
  543. WorldVolumesUpdatedMap.Add(World, false);
  544. }
  545. );
  546. m_SpatialAudioListener = nullptr;
  547. #if WITH_EDITORONLY_DATA
  548. if (!IsRunningGame())
  549. {
  550. static const FName kLevelEditorModuleName = TEXT("LevelEditor");
  551. auto MapChangedHandler = [this](UWorld* World, EMapChangeType MapChangeType)
  552. {
  553. if (World && World->AllowAudioPlayback() && World->WorldType == EWorldType::Editor)
  554. {
  555. if (MapChangeType == EMapChangeType::TearDownWorld)
  556. {
  557. if (EditorListener && World == EditorListener->GetWorld())
  558. {
  559. EditorListener->DestroyComponent();
  560. EditorListener = nullptr;
  561. }
  562. }
  563. else if (EditorListener == nullptr && MapChangeType != EMapChangeType::SaveMap)
  564. {
  565. EditorListener = CreateListener(World);
  566. // The Editor Listener should NEVER be the spatial audio listener
  567. if (m_SpatialAudioListener == EditorListener)
  568. {
  569. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  570. if (LIKELY(SpatialAudio))
  571. {
  572. SpatialAudio->UnregisterListener(m_SpatialAudioListener->GetAkGameObjectID());
  573. }
  574. m_SpatialAudioListener = nullptr;
  575. }
  576. }
  577. }
  578. };
  579. auto LevelEditorModulePtr = FModuleManager::Get().GetModulePtr<FLevelEditorModule>(kLevelEditorModuleName);
  580. if (LevelEditorModulePtr)
  581. {
  582. LevelEditorModulePtr->OnMapChanged().AddLambda(MapChangedHandler);
  583. }
  584. else
  585. {
  586. FModuleManager::Get().OnModulesChanged().AddLambda([this, MapChangedHandler](FName InModuleName, EModuleChangeReason Reason)
  587. {
  588. if (InModuleName == kLevelEditorModuleName && Reason == EModuleChangeReason::ModuleLoaded)
  589. {
  590. auto& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(kLevelEditorModuleName);
  591. LevelEditorModule.OnMapChanged().AddLambda(MapChangedHandler);
  592. }
  593. });
  594. }
  595. FWorldDelegates::OnPostWorldInitialization.AddLambda(
  596. [this](UWorld* World, const UWorld::InitializationValues IVS)
  597. {
  598. if (World && World->AllowAudioPlayback() && World->WorldType == EWorldType::Editor && EditorListener == nullptr)
  599. {
  600. EditorListener = CreateListener(World);
  601. // The Editor Listener should NEVER be the spatial audio listener
  602. if (m_SpatialAudioListener == EditorListener)
  603. {
  604. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  605. if (LIKELY(SpatialAudio))
  606. {
  607. SpatialAudio->UnregisterListener(m_SpatialAudioListener->GetAkGameObjectID());
  608. }
  609. m_SpatialAudioListener = nullptr;
  610. }
  611. }
  612. }
  613. );
  614. FWorldDelegates::OnWorldTickStart.AddLambda(
  615. [&](UWorld* World, ELevelTick LevelTick, float Tick)
  616. {
  617. if(World->WorldType != EWorldType::EditorPreview)
  618. {
  619. return;
  620. }
  621. auto& ViewportClients = GEditor->GetAllViewportClients();
  622. for(auto ViewportClient : ViewportClients)
  623. {
  624. if(ViewportClient->GetWorld() == World && ViewportClient->IsFocused(ViewportClient->Viewport))
  625. {
  626. auto Quat = ViewportClient->GetViewRotation().Quaternion();
  627. AkSoundPosition SoundPos;
  628. FVectorsToAKWorldTransform(
  629. ViewportClient->GetViewLocation(),
  630. Quat.GetForwardVector(),
  631. Quat.GetUpVector(),
  632. SoundPos
  633. );
  634. SetPosition(EditorListener, SoundPos);
  635. }
  636. }
  637. }
  638. );
  639. FEditorDelegates::OnEditorCameraMoved.AddLambda(
  640. [&](const FVector& Location, const FRotator& Rotation, ELevelViewportType ViewportType, int32 ViewIndex)
  641. {
  642. auto& allViewportClient = GEditor->GetAllViewportClients();
  643. if (allViewportClient[ViewIndex]->Viewport && allViewportClient[ViewIndex]->Viewport->HasFocus())
  644. {
  645. if (ListenerTransforms.Num() <= ViewIndex)
  646. {
  647. ListenerTransforms.AddDefaulted(ViewIndex - ListenerTransforms.Num() + 1);
  648. }
  649. ListenerTransforms[ViewIndex].SetLocation(Location);
  650. ListenerTransforms[ViewIndex].SetRotation(Rotation.Quaternion());
  651. UWorld * ViewportWorld = allViewportClient[ViewIndex]->GetWorld();
  652. if (ViewportWorld && ViewportWorld->WorldType != EWorldType::PIE)
  653. {
  654. auto Quat = Rotation.Quaternion();
  655. AkSoundPosition SoundPos;
  656. FVectorsToAKWorldTransform(
  657. Location,
  658. Quat.GetForwardVector(),
  659. Quat.GetUpVector(),
  660. SoundPos
  661. );
  662. SetPosition(EditorListener, SoundPos);
  663. }
  664. }
  665. }
  666. );
  667. FEditorDelegates::BeginPIE.AddRaw(this, &FAkAudioDevice::BeginPIE);
  668. FEditorDelegates::EndPIE.AddRaw(this, &FAkAudioDevice::EndPIE);
  669. FEditorDelegates::PausePIE.AddRaw(this, &FAkAudioDevice::PausePIE);
  670. FEditorDelegates::ResumePIE.AddRaw(this, &FAkAudioDevice::ResumePie);
  671. FEditorDelegates::OnSwitchBeginPIEAndSIE.AddRaw(this, &FAkAudioDevice::OnSwitchBeginPIEAndSIE);
  672. }
  673. #endif
  674. UE_LOG(LogAkAudio, Log, TEXT("Audiokinetic Audio Device initialized."));
  675. return 1;
  676. }
  677. #if WITH_EDITORONLY_DATA
  678. void FAkAudioDevice::BeginPIE(const bool bIsSimulating)
  679. {
  680. if (!bIsSimulating && EditorListener != nullptr)
  681. {
  682. RemoveDefaultListener(EditorListener);
  683. }
  684. else if (EditorListener == nullptr)
  685. {
  686. UE_LOG(LogAkAudio, Warning, TEXT("Undefined Behavior: EditorListener was set to null on BeginPIE."));
  687. }
  688. }
  689. void FAkAudioDevice::PausePIE(const bool bIsSimulating)
  690. {
  691. for (auto& Event: EventToPlayingIDMap)
  692. {
  693. for (auto PlayingID: Event.Value)
  694. {
  695. EAkAudioContext* Context = PlayingIDToAudioContextMap.Find(PlayingID);
  696. if (Context)
  697. {
  698. if (*Context == EAkAudioContext::GameplayAudio)
  699. {
  700. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  701. if (LIKELY(SoundEngine))
  702. {
  703. SoundEngine->ExecuteActionOnPlayingID(AK::SoundEngine::AkActionOnEventType_Pause, PlayingID);
  704. }
  705. }
  706. }
  707. }
  708. }
  709. }
  710. void FAkAudioDevice::ResumePie(const bool bIsSimulating)
  711. {
  712. for (auto& Event: EventToPlayingIDMap)
  713. {
  714. for (auto PlayingID: Event.Value)
  715. {
  716. EAkAudioContext* Context = PlayingIDToAudioContextMap.Find(PlayingID);
  717. if (Context)
  718. {
  719. if (*Context == EAkAudioContext::GameplayAudio)
  720. {
  721. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  722. if (LIKELY(SoundEngine))
  723. {
  724. SoundEngine->ExecuteActionOnPlayingID(AK::SoundEngine::AkActionOnEventType_Resume, PlayingID);
  725. }
  726. }
  727. }
  728. }
  729. }
  730. }
  731. void FAkAudioDevice::OnSwitchBeginPIEAndSIE(const bool bIsSimulating)
  732. {
  733. if(EditorListener != nullptr)
  734. {
  735. if (bIsSimulating)
  736. {
  737. AddDefaultListener(EditorListener);
  738. // The Editor Listener should NEVER be the spatial audio listener
  739. if (m_SpatialAudioListener == EditorListener)
  740. {
  741. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  742. if (LIKELY(SpatialAudio))
  743. {
  744. SpatialAudio->UnregisterListener(m_SpatialAudioListener->GetAkGameObjectID());
  745. }
  746. m_SpatialAudioListener = nullptr;
  747. }
  748. }
  749. else
  750. {
  751. RemoveDefaultListener(EditorListener);
  752. }
  753. }
  754. else
  755. {
  756. UE_LOG(LogAkAudio, Warning, TEXT("Undefined Behavior: EditorListener was set to null on SwitchBeginPIEAndSIE."));
  757. }
  758. }
  759. void FAkAudioDevice::EndPIE(const bool bIsSimulating)
  760. {
  761. //Reset Unreal Global gameobject to avoid complications from removing Spatial Audio listener
  762. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  763. if (LIKELY(SoundEngine))
  764. {
  765. AkGameObjectID tempID = DUMMY_GAMEOBJ;
  766. SoundEngine->SetListeners(DUMMY_GAMEOBJ, &tempID, 1);
  767. }
  768. if (!bIsSimulating && EditorListener != nullptr)
  769. {
  770. AddDefaultListener(EditorListener);
  771. // The Editor Listener should NEVER be the spatial audio listener
  772. if (m_SpatialAudioListener == EditorListener)
  773. {
  774. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  775. if (LIKELY(SpatialAudio))
  776. {
  777. SpatialAudio->UnregisterListener(m_SpatialAudioListener->GetAkGameObjectID());
  778. }
  779. m_SpatialAudioListener = nullptr;
  780. }
  781. }
  782. else if(EditorListener == nullptr)
  783. {
  784. UE_LOG(LogAkAudio, Warning, TEXT("Undefined Behavior: EditorListener was set to null on EndPIE."));
  785. }
  786. StopAllSounds();
  787. }
  788. #endif
  789. void FAkAudioDevice::UpdateRoomsForPortals()
  790. {
  791. #ifdef AK_ENABLE_ROOMS
  792. if (WorldsInNeedOfPortalRoomsUpdate.Num() == 0)
  793. {
  794. return;
  795. }
  796. for (auto& World : WorldsInNeedOfPortalRoomsUpdate)
  797. {
  798. auto Portals = WorldPortalsMap.Find(World);
  799. if (Portals != nullptr)
  800. {
  801. for (auto Portal : *Portals)
  802. {
  803. if (Portal.IsValid())
  804. {
  805. const bool RoomsChanged = Portal->UpdateConnectedRooms();
  806. if (RoomsChanged)
  807. SetSpatialAudioPortal(Portal.Get());
  808. }
  809. }
  810. }
  811. }
  812. WorldsInNeedOfPortalRoomsUpdate.Empty();
  813. #endif
  814. }
  815. void FAkAudioDevice::CleanupComponentMapsForWorld(UWorld* World)
  816. {
  817. LateReverbIndex.Clear(World);
  818. RoomIndex.Clear(World);
  819. WorldPortalsMap.Remove(World);
  820. OutdoorsConnectedPortals.Remove(World);
  821. }
  822. /**
  823. * Update the audio device and calculates the cached inverse transform later
  824. * on used for spatialization.
  825. */
  826. bool FAkAudioDevice::Update( float DeltaTime )
  827. {
  828. SCOPED_AKAUDIO_EVENT_2(TEXT("FAkAudioDevice::Update"));
  829. if (m_bSoundEngineInitialized)
  830. {
  831. UpdateRoomsForPortals();
  832. // Suspend audio when not in VR focus
  833. if (FApp::UseVRFocus())
  834. {
  835. if (FApp::HasVRFocus())
  836. {
  837. WakeupFromSuspend();
  838. }
  839. else
  840. {
  841. Suspend(true);
  842. }
  843. }
  844. UpdateSetCurrentAudioCultureAsyncTasks();
  845. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  846. if (UNLIKELY(!SoundEngine)) return false;
  847. SoundEngine->RenderAudio();
  848. }
  849. return true;
  850. }
  851. /**
  852. * Tears down audio device by stopping all sounds, removing all buffers,
  853. * destroying all sources, ... Called by both Destroy and ShutdownAfterError
  854. * to perform the actual tear down.
  855. */
  856. void FAkAudioDevice::Teardown()
  857. {
  858. SCOPED_AKAUDIO_EVENT_2(TEXT("FAkAudioDevice::Teardown"));
  859. #if AK_SUPPORT_WAAPI
  860. if (auto waapiClient = FAkWaapiClient::Get())
  861. {
  862. FAkAudioDevice_WaapiHelper::Unsubscribe(waapiClient, WaapiSubscriptionIds.Renamed);
  863. FAkAudioDevice_WaapiHelper::Unsubscribe(waapiClient, WaapiSubscriptionIds.PreDeleted);
  864. FAkAudioDevice_WaapiHelper::Unsubscribe(waapiClient, WaapiSubscriptionIds.ChildRemoved);
  865. FAkAudioDevice_WaapiHelper::Unsubscribe(waapiClient, WaapiSubscriptionIds.ChildAdded);
  866. FAkAudioDevice_WaapiHelper::Unsubscribe(waapiClient, WaapiSubscriptionIds.Created);
  867. if (ProjectLoadedHandle.IsValid())
  868. {
  869. waapiClient->OnProjectLoaded.Remove(ProjectLoadedHandle);
  870. ProjectLoadedHandle.Reset();
  871. }
  872. if (ConnectionLostHandle.IsValid())
  873. {
  874. waapiClient->OnConnectionLost.Remove(ConnectionLostHandle);
  875. ConnectionLostHandle.Reset();
  876. }
  877. if (ClientBeginDestroyHandle.IsValid())
  878. {
  879. waapiClient->OnClientBeginDestroy.Remove(ClientBeginDestroyHandle);
  880. ClientBeginDestroyHandle.Reset();
  881. }
  882. OnWwiseProjectModification.Clear();
  883. }
  884. #endif // AK_SUPPORT_WAAPI
  885. if (m_bSoundEngineInitialized)
  886. {
  887. m_EngineExiting = true;
  888. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  889. if (LIKELY(SoundEngine))
  890. {
  891. SoundEngine->UnregisterGameObj(DUMMY_GAMEOBJ);
  892. if (SoundEngine->IsInitialized())
  893. {
  894. FAkAudioDevice_Helpers::UnregisterAllGlobalCallbacks();
  895. SoundEngine->StopAll();
  896. SoundEngine->RenderAudio();
  897. }
  898. }
  899. FAkSoundEngineInitialization::Finalize(IOHook);
  900. if (LIKELY(CallbackManager))
  901. {
  902. delete CallbackManager;
  903. CallbackManager = nullptr;
  904. }
  905. if (LIKELY(CallbackInfoPool))
  906. {
  907. delete CallbackInfoPool;
  908. CallbackInfoPool = nullptr;
  909. }
  910. if (LIKELY(IOHook))
  911. {
  912. delete IOHook;
  913. IOHook = nullptr;
  914. }
  915. auto* Monitor = IWwiseMonitorAPI::Get();
  916. if (LIKELY(Monitor))
  917. {
  918. Monitor->TerminateDefaultWAAPIErrorTranslator();
  919. Monitor->ResetTranslator();
  920. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  921. delete m_UnrealErrorTranslator;
  922. m_UnrealErrorTranslator = nullptr;
  923. #endif
  924. }
  925. m_bSoundEngineInitialized = false;
  926. }
  927. FWorldDelegates::LevelRemovedFromWorld.RemoveAll(this);
  928. #if !WITH_EDITOR
  929. CachedUnrealToWwiseCulture.Empty();
  930. #endif
  931. UE_LOG(LogAkAudio, Log, TEXT("Audiokinetic Audio Device terminated."));
  932. }
  933. /**
  934. * Stops all game sounds (and possibly UI) sounds
  935. *
  936. * @param bShouldStopUISounds If true, this function will stop UI sounds as well
  937. */
  938. void FAkAudioDevice::StopAllSounds(bool bShouldStopUISounds)
  939. {
  940. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  941. if (UNLIKELY(!SoundEngine)) return;
  942. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  943. for (const auto& Event: EventToPlayingIDMap)
  944. {
  945. for (const auto& PlayingID: Event.Value)
  946. {
  947. if (EAkAudioContext* Context = PlayingIDToAudioContextMap.Find(PlayingID))
  948. {
  949. if (*Context == EAkAudioContext::GameplayAudio)
  950. {
  951. SoundEngine->StopPlayingID(PlayingID);
  952. }
  953. if (bShouldStopUISounds && *Context == EAkAudioContext::EditorAudio)
  954. {
  955. SoundEngine->StopPlayingID(PlayingID);
  956. }
  957. }
  958. }
  959. }
  960. }
  961. void FAkAudioDevice::StopAllSounds(EAkAudioContext AudioContext)
  962. {
  963. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  964. if (UNLIKELY(!SoundEngine)) return;
  965. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  966. for (const auto& Event: EventToPlayingIDMap)
  967. {
  968. for (const auto& PlayingID: Event.Value)
  969. {
  970. if (EAkAudioContext* Context = PlayingIDToAudioContextMap.Find(PlayingID))
  971. {
  972. if (*Context == AudioContext)
  973. {
  974. SoundEngine->StopPlayingID(PlayingID);
  975. }
  976. }
  977. }
  978. }
  979. }
  980. /**
  981. * Stop all audio associated with a scene
  982. *
  983. * @param SceneToFlush Interface of the scene to flush
  984. */
  985. void FAkAudioDevice::Flush(UWorld* WorldToFlush)
  986. {
  987. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  988. if (UNLIKELY(!SoundEngine)) return;
  989. StopAllSounds();
  990. }
  991. /**
  992. * Determine if any rooms or reverb volumes have been added to World during the current frame
  993. */
  994. bool FAkAudioDevice::WorldSpatialAudioVolumesUpdated(UWorld* World)
  995. {
  996. if (World == nullptr)
  997. return false;
  998. if (WorldVolumesUpdatedMap.Contains(World))
  999. return WorldVolumesUpdatedMap[World];
  1000. return false;
  1001. }
  1002. /**
  1003. * Clears all loaded SoundBanks and associated media
  1004. *
  1005. * @return Result from ak sound engine
  1006. */
  1007. void FAkAudioDevice::ClearSoundBanksAndMedia()
  1008. {
  1009. if (m_bSoundEngineInitialized)
  1010. {
  1011. StopAllSounds();
  1012. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1013. if (LIKELY(SoundEngine))
  1014. {
  1015. SoundEngine->RenderAudio();
  1016. FPlatformProcess::Sleep(0.1f);
  1017. }
  1018. }
  1019. for (TObjectIterator<UAkAudioType> AudioAssetIt; AudioAssetIt; ++AudioAssetIt)
  1020. {
  1021. AudioAssetIt->UnloadData();
  1022. }
  1023. }
  1024. AKRESULT FAkAudioDevice::LoadBank(
  1025. const FString& in_BankName,
  1026. AkBankID& out_bankID
  1027. )
  1028. {
  1029. AKRESULT eResult = AK_Fail;
  1030. if (EnsureInitialized()) // ensure audiolib is initialized
  1031. {
  1032. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1033. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1034. eResult = SoundEngine->LoadBank(TCHAR_TO_AK(*in_BankName), out_bankID);
  1035. }
  1036. if (eResult != AK_Success)
  1037. {
  1038. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::LoadBank: Failed to load bank %s. %s"), *in_BankName, WwiseUnrealHelper::GetResultString(eResult));
  1039. }
  1040. return eResult;
  1041. }
  1042. AKRESULT FAkAudioDevice::LoadBank(
  1043. const FString& in_BankName,
  1044. AkBankCallbackFunc in_pfnBankCallback,
  1045. void * in_pCookie,
  1046. AkBankID & out_bankID
  1047. )
  1048. {
  1049. if (EnsureInitialized()) // ensure audiolib is initialized
  1050. {
  1051. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1052. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1053. return SoundEngine->LoadBank(TCHAR_TO_AK(*in_BankName), in_pfnBankCallback, in_pCookie, out_bankID);
  1054. }
  1055. return AK_Fail;
  1056. }
  1057. AKRESULT FAkAudioDevice::LoadBank(
  1058. const FString& in_BankName,
  1059. FWaitEndBankAction* LoadBankLatentAction
  1060. )
  1061. {
  1062. if (EnsureInitialized()) // ensure audiolib is initialized
  1063. {
  1064. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1065. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1066. AkBankID BankId;
  1067. return SoundEngine->LoadBank(TCHAR_TO_AK(*in_BankName), nullptr, LoadBankLatentAction, BankId);
  1068. }
  1069. return AK_Fail;
  1070. }
  1071. AKRESULT FAkAudioDevice::LoadBankAsync(
  1072. const FString& in_BankName,
  1073. const FOnAkBankCallback& BankLoadedCallback,
  1074. AkBankID & out_bankID
  1075. )
  1076. {
  1077. if (EnsureInitialized()) // ensure audiolib is initialized
  1078. {
  1079. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1080. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1081. return SoundEngine->LoadBank(TCHAR_TO_AK(*in_BankName), out_bankID);
  1082. }
  1083. return AK_Fail;
  1084. }
  1085. AKRESULT FAkAudioDevice::LoadBankFromMemory(
  1086. const void* MemoryPtr,
  1087. uint32 MemorySize,
  1088. AkBankType BankType,
  1089. AkBankID& OutBankID
  1090. )
  1091. {
  1092. if (EnsureInitialized() && MemoryPtr && MemorySize > 0)
  1093. {
  1094. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1095. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1096. return SoundEngine->LoadBankMemoryView(MemoryPtr, MemorySize, OutBankID, BankType);
  1097. }
  1098. return AK_Fail;
  1099. }
  1100. AKRESULT FAkAudioDevice::UnloadBank(
  1101. const FString& in_BankName
  1102. )
  1103. {
  1104. AKRESULT eResult = AK_Fail;
  1105. if ( m_bSoundEngineInitialized )
  1106. {
  1107. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1108. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1109. eResult = SoundEngine->UnloadBank(TCHAR_TO_AK(*in_BankName), nullptr );
  1110. }
  1111. if (eResult != AK_Success)
  1112. {
  1113. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::UnloadBank: Failed to unload bank %s. %s"), *in_BankName, WwiseUnrealHelper::GetResultString(eResult));
  1114. }
  1115. return eResult;
  1116. }
  1117. AKRESULT FAkAudioDevice::UnloadBank(
  1118. const FString& in_BankName,
  1119. AkBankCallbackFunc in_pfnBankCallback,
  1120. void * in_pCookie
  1121. )
  1122. {
  1123. if (m_bSoundEngineInitialized)
  1124. {
  1125. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1126. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1127. return SoundEngine->UnloadBank(TCHAR_TO_AK(*in_BankName), NULL, in_pfnBankCallback, in_pCookie);
  1128. }
  1129. return AK_Fail;
  1130. }
  1131. AKRESULT FAkAudioDevice::UnloadBank(
  1132. const FString& in_BankName,
  1133. FWaitEndBankAction* UnloadBankLatentAction
  1134. )
  1135. {
  1136. if (m_bSoundEngineInitialized)
  1137. {
  1138. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1139. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1140. return SoundEngine->UnloadBank(TCHAR_TO_AK(*in_BankName), nullptr);
  1141. }
  1142. return AK_Fail;
  1143. }
  1144. AKRESULT FAkAudioDevice::UnloadBankFromMemory(
  1145. AkBankID in_bankID,
  1146. const void* in_memoryPtr
  1147. )
  1148. {
  1149. if (EnsureInitialized() && in_memoryPtr)
  1150. {
  1151. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1152. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1153. return SoundEngine->UnloadBank(in_bankID, in_memoryPtr);
  1154. }
  1155. return AK_Fail;
  1156. }
  1157. AKRESULT FAkAudioDevice::UnloadBankFromMemoryAsync(
  1158. AkBankID in_bankID,
  1159. const void* in_memoryPtr,
  1160. AkBankCallbackFunc in_pfnBankCallback,
  1161. void* in_pCookie,
  1162. uint32 BankType
  1163. )
  1164. {
  1165. if (EnsureInitialized() && in_memoryPtr)
  1166. {
  1167. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1168. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1169. return SoundEngine->UnloadBank(in_bankID, in_memoryPtr, in_pfnBankCallback, in_pCookie, BankType);
  1170. }
  1171. return AK_Fail;
  1172. }
  1173. AKRESULT FAkAudioDevice::UnloadBankAsync(
  1174. const FString& in_BankName,
  1175. const FOnAkBankCallback& BankUnloadedCallback
  1176. )
  1177. {
  1178. if (m_bSoundEngineInitialized)
  1179. {
  1180. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1181. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1182. return SoundEngine->UnloadBank(TCHAR_TO_AK(*in_BankName), nullptr);
  1183. }
  1184. return AK_Fail;
  1185. }
  1186. AkUInt32 FAkAudioDevice::GetShortIDFromString(const FString& InString)
  1187. {
  1188. if (InString.IsEmpty())
  1189. {
  1190. return AK_INVALID_UNIQUE_ID;
  1191. }
  1192. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1193. if (UNLIKELY(!SoundEngine)) return AK_INVALID_UNIQUE_ID;
  1194. return SoundEngine->GetIDFromString(TCHAR_TO_ANSI(*InString));
  1195. }
  1196. AkUInt32 FAkAudioDevice::GetShortID(UAkAudioType* AudioAsset, const FString& BackupName)
  1197. {
  1198. AkUInt32 ShortId;
  1199. if (AudioAsset)
  1200. {
  1201. ShortId = AudioAsset->GetShortID();
  1202. }
  1203. else
  1204. {
  1205. ShortId = GetShortIDFromString(BackupName);
  1206. }
  1207. if (ShortId == AK_INVALID_UNIQUE_ID)
  1208. {
  1209. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::GetShortID : Returning invalid ShortId for Wwise Object named %s."), AudioAsset? *AudioAsset->GetName() : *BackupName);
  1210. }
  1211. return ShortId;
  1212. }
  1213. AKRESULT FAkAudioDevice::SetMedia(AkSourceSettings* in_pSourceSettings, uint32 in_uNumSourceSettings)
  1214. {
  1215. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1216. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1217. return SoundEngine->SetMedia(in_pSourceSettings, in_uNumSourceSettings);
  1218. }
  1219. AKRESULT FAkAudioDevice::TryUnsetMedia(AkSourceSettings* in_pSourceSettings, uint32 in_uNumSourceSettings, AKRESULT* out_pUnsetResults)
  1220. {
  1221. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1222. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1223. return SoundEngine->TryUnsetMedia(in_pSourceSettings, in_uNumSourceSettings, out_pUnsetResults);
  1224. }
  1225. AKRESULT FAkAudioDevice::UnsetMedia(AkSourceSettings* in_pSourceSettings, uint32 in_uNumSourceSettings)
  1226. {
  1227. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1228. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1229. return SoundEngine->UnsetMedia(in_pSourceSettings, in_uNumSourceSettings);
  1230. }
  1231. FString FAkAudioDevice::GetCurrentAudioCulture() const
  1232. {
  1233. auto* StreamMgr = IWwiseStreamMgrAPI::Get();
  1234. if (UNLIKELY(!StreamMgr))
  1235. {
  1236. return {};
  1237. }
  1238. return FString(StreamMgr->GetCurrentLanguage());
  1239. }
  1240. FString FAkAudioDevice::GetDefaultLanguage()
  1241. {
  1242. auto* WwiseInitBankLoader = FWwiseInitBankLoader::Get();
  1243. if (LIKELY(WwiseInitBankLoader))
  1244. {
  1245. auto* InitBankAsset = WwiseInitBankLoader->GetInitBankAsset();
  1246. if (LIKELY(InitBankAsset))
  1247. {
  1248. TArray<FWwiseLanguageCookedData> Languages = InitBankAsset->GetLanguages();
  1249. for (auto& Language : Languages)
  1250. {
  1251. if (Language.LanguageRequirement == EWwiseLanguageRequirement::IsDefault)
  1252. {
  1253. return Language.LanguageName.ToString();
  1254. }
  1255. }
  1256. }
  1257. else
  1258. {
  1259. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::GetDefaultLanguage: Could not get AkInitBank asset, returning empty language."));
  1260. }
  1261. }
  1262. else
  1263. {
  1264. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::GetDefaultLanguage: Could not get WwiseInitBankLoader, returning empty language."));
  1265. }
  1266. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::GetDefaultLanguage: Could not find default language in available languages list."));
  1267. return {};
  1268. }
  1269. TArray<FString> FAkAudioDevice::GetAvailableAudioCultures() const
  1270. {
  1271. auto* WwiseInitBankLoader = FWwiseInitBankLoader::Get();
  1272. if (UNLIKELY(!WwiseInitBankLoader))
  1273. {
  1274. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::GetAvailableAudioCultures: Could not get WwiseInitBankLoader, returning empty list."));
  1275. return {};
  1276. }
  1277. auto* InitBankAsset = WwiseInitBankLoader->GetInitBankAsset();
  1278. if (UNLIKELY(!InitBankAsset))
  1279. {
  1280. UE_LOG(LogAkAudio, Warning, TEXT("FAkAudioDevice::GetAvailableAudioCultures: Could not get AkInitBank asset, returning empty list."));
  1281. return {};
  1282. }
  1283. TSet<FString> LanguageNames;
  1284. for(const auto& Language : InitBankAsset->InitBankCookedData.Language)
  1285. {
  1286. LanguageNames.Add(Language.LanguageName.ToString());
  1287. }
  1288. return LanguageNames.Array();
  1289. }
  1290. FWwiseLanguageCookedData FAkAudioDevice::GetLanguageCookedDataFromString(const FString& WwiseLanguage)
  1291. {
  1292. auto* WwiseInitBankLoader = FWwiseInitBankLoader::Get();
  1293. if (LIKELY(WwiseInitBankLoader))
  1294. {
  1295. auto* InitBankAsset = WwiseInitBankLoader->GetInitBankAsset();
  1296. if (LIKELY(InitBankAsset))
  1297. {
  1298. for (auto& Language : InitBankAsset->InitBankCookedData.Language)
  1299. {
  1300. if (Language.LanguageName.ToString() == WwiseLanguage)
  1301. {
  1302. return FWwiseLanguageCookedData(Language.LanguageId, Language.LanguageName, Language.LanguageRequirement);
  1303. }
  1304. }
  1305. }
  1306. }
  1307. return FWwiseLanguageCookedData(GetShortIDFromString(WwiseLanguage), FName(WwiseLanguage), EWwiseLanguageRequirement::IsOptional);
  1308. }
  1309. void FAkAudioDevice::SetCurrentAudioCulture(const FString& NewAudioCulture)
  1310. {
  1311. FString NewWwiseLanguage;
  1312. if (FindWwiseLanguage(NewAudioCulture, NewWwiseLanguage))
  1313. {
  1314. auto* ResourceLoader = FWwiseResourceLoader::Get();
  1315. if (UNLIKELY(!ResourceLoader))
  1316. {
  1317. return;
  1318. }
  1319. ResourceLoader->SetLanguage(GetLanguageCookedDataFromString(NewWwiseLanguage), EWwiseReloadLanguage::Immediate);
  1320. auto* StreamMgr = IWwiseStreamMgrAPI::Get();
  1321. if (UNLIKELY(!StreamMgr))
  1322. {
  1323. return;
  1324. }
  1325. StreamMgr->SetCurrentLanguage(TCHAR_TO_AK(*NewWwiseLanguage));
  1326. }
  1327. }
  1328. void FAkAudioDevice::SetCurrentAudioCultureAsync(const FString& NewAudioCulture, FSetCurrentAudioCultureAction* LatentAction)
  1329. {
  1330. FString NewWwiseLanguage;
  1331. if (FindWwiseLanguage(NewAudioCulture, NewWwiseLanguage))
  1332. {
  1333. SetCurrentAudioCultureAsyncTask* newTask = new SetCurrentAudioCultureAsyncTask(GetLanguageCookedDataFromString(NewWwiseLanguage), LatentAction);
  1334. if (newTask->Start())
  1335. {
  1336. AudioCultureAsyncTasks.Add(newTask);
  1337. }
  1338. else
  1339. {
  1340. LatentAction->ActionDone = true;
  1341. delete newTask;
  1342. }
  1343. }
  1344. else
  1345. {
  1346. LatentAction->ActionDone = true;
  1347. }
  1348. }
  1349. void FAkAudioDevice::SetCurrentAudioCultureAsync(const FString& NewAudioCulture, const FOnSetCurrentAudioCultureCompleted& CompletedCallback)
  1350. {
  1351. FString NewWwiseLanguage;
  1352. if (FindWwiseLanguage(NewAudioCulture, NewWwiseLanguage))
  1353. {
  1354. SetCurrentAudioCultureAsyncTask* newTask = new SetCurrentAudioCultureAsyncTask(GetLanguageCookedDataFromString(NewWwiseLanguage), CompletedCallback);
  1355. if (newTask->Start())
  1356. {
  1357. AudioCultureAsyncTasks.Add(newTask);
  1358. }
  1359. else
  1360. {
  1361. CompletedCallback.ExecuteIfBound(false);
  1362. delete newTask;
  1363. }
  1364. }
  1365. else
  1366. {
  1367. CompletedCallback.ExecuteIfBound(true);
  1368. }
  1369. }
  1370. bool FAkAudioDevice::FindWwiseLanguage(const FString& NewAudioCulture, FString& FoundWwiseLanguage)
  1371. {
  1372. auto oldAudioCulture = GetCurrentAudioCulture();
  1373. FoundWwiseLanguage = NewAudioCulture;
  1374. auto newCulturePtr = FInternationalization::Get().GetCulture(FoundWwiseLanguage);
  1375. if (newCulturePtr && newCulturePtr->GetLCID() != InvariantLCID)
  1376. {
  1377. auto& newLanguage = newCulturePtr->GetTwoLetterISOLanguageName();
  1378. auto& newRegion = newCulturePtr->GetRegion();
  1379. auto& newScript = newCulturePtr->GetScript();
  1380. int maxMatch = 0;
  1381. auto findMostCompatibleCulture = [&maxMatch, &newLanguage, &newRegion, &newScript, &FoundWwiseLanguage](const FCulturePtr& currentCulture, const FString& currentValue) {
  1382. auto& currentLanguageName = currentCulture->GetTwoLetterISOLanguageName();
  1383. auto& currentRegionName = currentCulture->GetRegion();
  1384. auto& currentScript = currentCulture->GetScript();
  1385. int currentMatch = 0;
  1386. if (currentLanguageName == newLanguage)
  1387. {
  1388. currentMatch = 1;
  1389. // This is inspired by how UE processes culture from most to least specific. For example:
  1390. // zh - Hans - CN is processed as "zh-Hans-CN", then "zh-CN", then "zh-Hans", then "zh".
  1391. // This is how I selected the weight for each match.
  1392. if (!currentScript.IsEmpty() && !newScript.IsEmpty()
  1393. && !currentRegionName.IsEmpty() && !newRegion.IsEmpty())
  1394. {
  1395. if (currentScript == newScript && currentRegionName == newRegion)
  1396. {
  1397. currentMatch += 4;
  1398. }
  1399. else
  1400. {
  1401. --currentMatch;
  1402. }
  1403. }
  1404. if (!currentRegionName.IsEmpty() && !newRegion.IsEmpty())
  1405. {
  1406. if (currentRegionName == newRegion)
  1407. {
  1408. currentMatch += 3;
  1409. }
  1410. else
  1411. {
  1412. --currentMatch;
  1413. }
  1414. }
  1415. if (!currentScript.IsEmpty() && !newScript.IsEmpty())
  1416. {
  1417. if (currentScript == newScript)
  1418. {
  1419. currentMatch += 2;
  1420. }
  1421. else
  1422. {
  1423. --currentMatch;
  1424. }
  1425. }
  1426. }
  1427. if (currentMatch > 0)
  1428. {
  1429. // When the current culture is missing script or region but the new culture
  1430. // has it, give a weight boost of 1
  1431. if (!newScript.IsEmpty() && currentScript.IsEmpty())
  1432. {
  1433. ++currentMatch;
  1434. }
  1435. if (!newRegion.IsEmpty() && currentRegionName.IsEmpty())
  1436. {
  1437. ++currentMatch;
  1438. }
  1439. }
  1440. if (maxMatch < currentMatch)
  1441. {
  1442. FoundWwiseLanguage = currentValue;
  1443. maxMatch = currentMatch;
  1444. }
  1445. };
  1446. #if WITH_EDITOR
  1447. if (auto* akSettings = GetDefault<UAkSettings>())
  1448. {
  1449. for (auto& entry : akSettings->UnrealCultureToWwiseCulture)
  1450. {
  1451. auto currentCulture = FInternationalization::Get().GetCulture(entry.Key);
  1452. if (currentCulture && currentCulture->GetLCID() != InvariantLCID)
  1453. {
  1454. findMostCompatibleCulture(currentCulture, entry.Value);
  1455. }
  1456. }
  1457. }
  1458. #else
  1459. for (auto& entry : CachedUnrealToWwiseCulture)
  1460. {
  1461. findMostCompatibleCulture(entry.Key, entry.Value);
  1462. }
  1463. #endif
  1464. }
  1465. return oldAudioCulture != FoundWwiseLanguage;
  1466. }
  1467. void FAkAudioDevice::UpdateSetCurrentAudioCultureAsyncTasks()
  1468. {
  1469. if(AudioCultureAsyncTasks.Num() == 0)
  1470. {
  1471. return;
  1472. }
  1473. for (auto task : AudioCultureAsyncTasks)
  1474. {
  1475. task->Update();
  1476. }
  1477. for (int32 i = AudioCultureAsyncTasks.Num() - 1; i >= 0; --i)
  1478. {
  1479. if (AudioCultureAsyncTasks[i]->IsDone)
  1480. {
  1481. delete AudioCultureAsyncTasks[i];
  1482. AudioCultureAsyncTasks[i] = nullptr;
  1483. }
  1484. }
  1485. AudioCultureAsyncTasks.RemoveAll([](SetCurrentAudioCultureAsyncTask* Task) { return Task == nullptr; });
  1486. }
  1487. template<typename FCreateCallbackPackage>
  1488. AkPlayingID FAkAudioDevice::PostEventWithCallbackPackageOnAkGameObject(
  1489. const AkUInt32 EventShortID,
  1490. UAkGameObject* GameObject,
  1491. const TArray<AkExternalSourceInfo>& ExternalSources,
  1492. FCreateCallbackPackage CreateCallbackPackage,
  1493. EAkAudioContext AudioContext
  1494. )
  1495. {
  1496. AkPlayingID PlayingID = AK_INVALID_PLAYING_ID;
  1497. if (m_bSoundEngineInitialized && GameObject && CallbackManager)
  1498. {
  1499. if (EventShortID != AK_INVALID_UNIQUE_ID && GameObject->AllowAudioPlayback())
  1500. {
  1501. GameObject->UpdateObstructionAndOcclusion();
  1502. auto gameObjID = GameObject->GetAkGameObjectID();
  1503. PlayingID = PostEventWithCallbackPackageOnGameObjectId(EventShortID, gameObjID, ExternalSources, CreateCallbackPackage, AudioContext);
  1504. if (PlayingID != AK_INVALID_PLAYING_ID)
  1505. {
  1506. GameObject->EventPosted();
  1507. }
  1508. }
  1509. }
  1510. return PlayingID;
  1511. }
  1512. void FAkAudioDevice::SAComponentAddedRemoved(UWorld* World)
  1513. {
  1514. if (World != nullptr)
  1515. {
  1516. if (WorldVolumesUpdatedMap.Contains(World))
  1517. WorldVolumesUpdatedMap[World] = true;
  1518. else
  1519. WorldVolumesUpdatedMap.Add(World, true);
  1520. }
  1521. }
  1522. /** Find UAkLateReverbComponents at a given location. */
  1523. TArray<class UAkLateReverbComponent*> FAkAudioDevice::FindLateReverbComponentsAtLocation(const FVector& Loc, const UWorld* World)
  1524. {
  1525. return LateReverbIndex.Query<UAkLateReverbComponent>(Loc, World);
  1526. }
  1527. /** Add a UAkLateReverbComponent to the linked list. */
  1528. void FAkAudioDevice::IndexLateReverb(class UAkLateReverbComponent* ComponentToAdd)
  1529. {
  1530. check(!ComponentToAdd->IsIndexed);
  1531. LateReverbIndex.Add(ComponentToAdd);
  1532. SAComponentAddedRemoved(ComponentToAdd->GetWorld());
  1533. ComponentToAdd->IsIndexed = true;
  1534. }
  1535. /** Remove a UAkLateReverbComponent from the linked list. */
  1536. void FAkAudioDevice::UnindexLateReverb(class UAkLateReverbComponent* ComponentToRemove)
  1537. {
  1538. check(ComponentToRemove->IsIndexed);
  1539. if (LateReverbIndex.Remove(ComponentToRemove))
  1540. {
  1541. SAComponentAddedRemoved(ComponentToRemove->GetWorld());
  1542. }
  1543. ComponentToRemove->IsIndexed = false;
  1544. }
  1545. void FAkAudioDevice::ReindexLateReverb(class UAkLateReverbComponent* ComponentToUpdate)
  1546. {
  1547. check(ComponentToUpdate->IsIndexed);
  1548. LateReverbIndex.Update(ComponentToUpdate);
  1549. SAComponentAddedRemoved(ComponentToUpdate->GetWorld());
  1550. }
  1551. bool FAkAudioDevice::WorldHasActiveRooms(UWorld* World)
  1552. {
  1553. return !RoomIndex.IsEmpty(World);
  1554. }
  1555. /** Find UAkRoomComponents at a given location. */
  1556. TArray<class UAkRoomComponent*> FAkAudioDevice::FindRoomComponentsAtLocation(const FVector& Loc, const UWorld* World)
  1557. {
  1558. return RoomIndex.Query<UAkRoomComponent>(Loc, World);
  1559. }
  1560. /** Add a UAkRoomComponent to the linked list. */
  1561. void FAkAudioDevice::IndexRoom(class UAkRoomComponent* ComponentToAdd)
  1562. {
  1563. RoomIndex.Add(ComponentToAdd);
  1564. SAComponentAddedRemoved(ComponentToAdd->GetWorld());
  1565. }
  1566. /** Remove a UAkRoomComponent from the linked list. */
  1567. void FAkAudioDevice::UnindexRoom(class UAkRoomComponent* ComponentToRemove)
  1568. {
  1569. if (RoomIndex.Remove(ComponentToRemove))
  1570. {
  1571. SAComponentAddedRemoved(ComponentToRemove->GetWorld());
  1572. }
  1573. }
  1574. void FAkAudioDevice::ReindexRoom(class UAkRoomComponent* ComponentToAdd)
  1575. {
  1576. RoomIndex.Update(ComponentToAdd);
  1577. SAComponentAddedRemoved(ComponentToAdd->GetWorld());
  1578. }
  1579. /** Return true if any UAkRoomComponents have been added to the prioritized list of rooms **/
  1580. bool FAkAudioDevice::UsingSpatialAudioRooms(const UWorld* World)
  1581. {
  1582. return !RoomIndex.IsEmpty(World);
  1583. }
  1584. /** Seek on an event in the ak soundengine.
  1585. * @param EventShortID Name of the event on which to seek.
  1586. * @param Actor The associated Actor. If this is nullptr, defaul object will be used.
  1587. * @param in_fPercent Desired percent where playback should restart.
  1588. * @param in_bSeekToNearestMarker If true, the final seeking position will be made equal to the nearest marker.
  1589. *
  1590. * @return Success or failure.
  1591. */
  1592. AKRESULT FAkAudioDevice::SeekOnEvent(
  1593. const AkUInt32 EventShortID,
  1594. AActor* Actor,
  1595. AkReal32 Percent,
  1596. bool bSeekToNearestMarker /*= false*/,
  1597. AkPlayingID PlayingID /*= AK_INVALID_PLAYING_ID*/
  1598. )
  1599. {
  1600. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1601. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1602. if (!Actor)
  1603. {
  1604. // SeekOnEvent must be bound to a game object. Passing DUMMY_GAMEOBJ as default game object.
  1605. return SoundEngine->SeekOnEvent(EventShortID, DUMMY_GAMEOBJ, Percent, bSeekToNearestMarker, PlayingID);
  1606. }
  1607. else if (!Actor->IsActorBeingDestroyed() && IsValid(Actor))
  1608. {
  1609. UAkComponent* pComponent = GetAkComponent(Actor->GetRootComponent(), FName(), NULL, EAttachLocation::KeepRelativeOffset);
  1610. if (pComponent)
  1611. {
  1612. return SeekOnEvent(EventShortID, pComponent, Percent, bSeekToNearestMarker, PlayingID);
  1613. }
  1614. }
  1615. return AKRESULT::AK_Fail;
  1616. }
  1617. /** Seek on an event in the ak soundengine.
  1618. * @param EventShortID Name of the event on which to seek.
  1619. * @param Component The associated AkComponent.
  1620. * @param in_fPercent Desired percent where playback should restart.
  1621. * @param in_bSeekToNearestMarker If true, the final seeking position will be made equal to the nearest marker.
  1622. *
  1623. * @return Success or failure.
  1624. */
  1625. AKRESULT FAkAudioDevice::SeekOnEvent(
  1626. const AkUInt32 EventShortID,
  1627. UAkComponent* Component,
  1628. AkReal32 Percent,
  1629. bool bSeekToNearestMarker /*= false*/,
  1630. AkPlayingID PlayingID /*= AK_INVALID_PLAYING_ID*/
  1631. )
  1632. {
  1633. if (m_bSoundEngineInitialized && Component)
  1634. {
  1635. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1636. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1637. if (Component->AllowAudioPlayback())
  1638. {
  1639. return SoundEngine->SeekOnEvent(EventShortID, Component->GetAkGameObjectID(), Percent, bSeekToNearestMarker, PlayingID);
  1640. }
  1641. }
  1642. return AKRESULT::AK_Fail;
  1643. }
  1644. void FAkAudioDevice::UpdateAllSpatialAudioPortals(UWorld* InWorld)
  1645. {
  1646. #ifdef AK_ENABLE_PORTALS
  1647. auto Portals = WorldPortalsMap.Find(InWorld);
  1648. if (Portals != nullptr)
  1649. {
  1650. for (auto Portal : *Portals)
  1651. {
  1652. if (Portal.IsValid())
  1653. {
  1654. SetSpatialAudioPortal(Portal.Get());
  1655. }
  1656. }
  1657. }
  1658. #endif
  1659. }
  1660. void FAkAudioDevice::SetSpatialAudioPortal(UAkPortalComponent* in_Portal)
  1661. {
  1662. if(!IsValid(in_Portal) || IsRunningCommandlet())
  1663. return;
  1664. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  1665. if (UNLIKELY(!SpatialAudio)) return;
  1666. #ifdef AK_ENABLE_PORTALS
  1667. UWorld* World = in_Portal->GetWorld();
  1668. auto Portals = WorldPortalsMap.Find(World);
  1669. if (Portals == nullptr)
  1670. Portals = &WorldPortalsMap.Add(World, TArray<TWeakObjectPtr<UAkPortalComponent>>());
  1671. if (Portals != nullptr)
  1672. {
  1673. if (!Portals->Contains(in_Portal))
  1674. {
  1675. Portals->Add(in_Portal);
  1676. }
  1677. }
  1678. /* Only update the sound engine for game worlds. */
  1679. if (ShouldNotifySoundEngine(World->WorldType))
  1680. {
  1681. AkPortalID portalID = in_Portal->GetPortalID();
  1682. if (!in_Portal->PortalPlacementValid())
  1683. {
  1684. SpatialAudio->RemovePortal(portalID);
  1685. UE_LOG(LogAkAudio, Log, TEXT("UAkPortalComponent %s must have a front room which is distinct from its back room."), *(in_Portal->GetOwner() != nullptr ? in_Portal->GetOwner()->GetName() : in_Portal->GetName()));
  1686. }
  1687. else
  1688. {
  1689. FString nameStr = in_Portal->GetName();
  1690. AActor* portalOwner = in_Portal->GetOwner();
  1691. UPrimitiveComponent* primitiveParent = in_Portal->GetPrimitiveParent();
  1692. if (portalOwner != nullptr)
  1693. {
  1694. #if WITH_EDITOR
  1695. nameStr = portalOwner->GetActorLabel();
  1696. #else
  1697. nameStr = portalOwner->GetName();
  1698. #endif
  1699. if (primitiveParent != nullptr)
  1700. {
  1701. // ensures unique and meaningful names when we have multiple portals in the same actor.
  1702. TInlineComponentArray<UAkPortalComponent*> PortalComponents;
  1703. portalOwner->GetComponents(PortalComponents);
  1704. if (PortalComponents.Num() > 1)
  1705. nameStr.Append(FString("_").Append(primitiveParent->GetName()));
  1706. }
  1707. }
  1708. AkPortalParams Params;
  1709. UPrimitiveComponent* Parent = in_Portal->GetPrimitiveParent();
  1710. if (IsValid(Parent))
  1711. {
  1712. AkComponentHelpers::GetPrimitiveTransformAndExtent(*Parent, Params.Transform, Params.Extent);
  1713. }
  1714. Params.bEnabled = in_Portal->GetCurrentState() == AkAcousticPortalState::Open;
  1715. Params.FrontRoom = in_Portal->GetFrontRoomID();
  1716. Params.BackRoom = in_Portal->GetBackRoomID();
  1717. SpatialAudio->SetPortal(portalID, Params, TCHAR_TO_ANSI(*nameStr));
  1718. }
  1719. }
  1720. #endif
  1721. }
  1722. void FAkAudioDevice::RemoveSpatialAudioPortal(UAkPortalComponent* in_Portal)
  1723. {
  1724. if (IsRunningCommandlet())
  1725. return;
  1726. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  1727. if (UNLIKELY(!SpatialAudio)) return;
  1728. #ifdef AK_ENABLE_PORTALS
  1729. auto Portals = WorldPortalsMap.Find(in_Portal->GetWorld());
  1730. if (Portals != nullptr && Portals->Contains(in_Portal))
  1731. {
  1732. Portals->Remove(in_Portal);
  1733. }
  1734. if (ShouldNotifySoundEngine(in_Portal->GetWorld()->WorldType))
  1735. {
  1736. AkPortalID portalID = in_Portal->GetPortalID();
  1737. SpatialAudio->RemovePortal(portalID);
  1738. }
  1739. #endif
  1740. }
  1741. /** Get a sorted list of AkAuxSendValue at a location
  1742. *
  1743. * @param Loc Location at which to find Reverb Volumes
  1744. * @param AkReverbVolumes Array of AkAuxSendValue at this location
  1745. */
  1746. void FAkAudioDevice::GetAuxSendValuesAtLocation(FVector Loc, TArray<AkAuxSendValue>& AkAuxSendValues, const UWorld* in_World)
  1747. {
  1748. // Check if there are AkReverbVolumes at this location
  1749. TArray<UAkLateReverbComponent*> FoundComponents = LateReverbIndex.Query<UAkLateReverbComponent>(Loc, in_World);
  1750. // Sort the found Volumes
  1751. if (FoundComponents.Num() > 1)
  1752. {
  1753. FoundComponents.Sort([](const UAkLateReverbComponent& A, const UAkLateReverbComponent& B)
  1754. {
  1755. return A.Priority > B.Priority;
  1756. });
  1757. }
  1758. // Apply the found Aux Sends
  1759. AkAuxSendValue TmpSendValue;
  1760. // Build a list to set as AuxBusses
  1761. for( uint8 Idx = 0; Idx < FoundComponents.Num() && Idx < MaxAuxBus; Idx++ )
  1762. {
  1763. TmpSendValue.listenerID = AK_INVALID_GAME_OBJECT;
  1764. TmpSendValue.auxBusID = FoundComponents[Idx]->GetAuxBusId();
  1765. TmpSendValue.fControlValue = FoundComponents[Idx]->SendLevel;
  1766. AkAuxSendValues.Add(TmpSendValue);
  1767. }
  1768. }
  1769. void FAkAudioDevice::PostEventAtLocationEndOfEventCallback(AkCallbackType in_eType, AkCallbackInfo* in_pCallbackInfo)
  1770. {
  1771. if (auto* Device = FAkAudioDevice::Get())
  1772. {
  1773. Device->RemovePlayingID(((AkEventCallbackInfo*)in_pCallbackInfo)->eventID, ((AkEventCallbackInfo*)in_pCallbackInfo)->playingID);
  1774. auto pPackage = (IAkUserEventCallbackPackage*)in_pCallbackInfo->pCookie;
  1775. if (pPackage && pPackage->HasExternalSources)
  1776. {
  1777. if (auto* ExternalSourceManager = IWwiseExternalSourceManager::Get())
  1778. {
  1779. ExternalSourceManager->OnEndOfEvent(((AkEventCallbackInfo*)in_pCallbackInfo)->playingID);
  1780. }
  1781. }
  1782. }
  1783. }
  1784. UAkComponent* FAkAudioDevice::SpawnAkComponentAtLocation( class UAkAudioEvent* in_pAkEvent, FVector Location, FRotator Orientation, bool AutoPost, const FString& EventName, bool AutoDestroy, UWorld* in_World)
  1785. {
  1786. UAkComponent * AkComponent = NULL;
  1787. if (in_World)
  1788. {
  1789. AkComponent = NewObject<UAkComponent>(in_World->GetWorldSettings());
  1790. }
  1791. else
  1792. {
  1793. AkComponent = NewObject<UAkComponent>();
  1794. }
  1795. if( AkComponent )
  1796. {
  1797. AkComponent->AkAudioEvent = in_pAkEvent;
  1798. AkComponent->SetWorldLocationAndRotation(Location, Orientation.Quaternion());
  1799. if(in_World)
  1800. {
  1801. AkComponent->RegisterComponentWithWorld(in_World);
  1802. }
  1803. AkComponent->SetAutoDestroy(AutoDestroy);
  1804. if(AutoPost)
  1805. {
  1806. if (AkComponent->PostAssociatedAkEvent(0, FOnAkPostEventCallback()) == AK_INVALID_PLAYING_ID && AutoDestroy)
  1807. {
  1808. AkComponent->ConditionalBeginDestroy();
  1809. AkComponent = NULL;
  1810. }
  1811. }
  1812. }
  1813. return AkComponent;
  1814. }
  1815. /**
  1816. * Post a trigger to ak soundengine
  1817. *
  1818. * @param in_pszTrigger Name of the trigger
  1819. * @param in_pAkComponent AkComponent on which to post the trigger
  1820. * @return Result from ak sound engine
  1821. */
  1822. AKRESULT FAkAudioDevice::PostTrigger(
  1823. const TCHAR * in_pszTrigger,
  1824. AActor * in_pActor
  1825. )
  1826. {
  1827. AkGameObjectID GameObjID = AK_INVALID_GAME_OBJECT;
  1828. AKRESULT eResult = GetGameObjectID( in_pActor, GameObjID );
  1829. if ( m_bSoundEngineInitialized && eResult == AK_Success)
  1830. {
  1831. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1832. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1833. eResult = SoundEngine->PostTrigger(TCHAR_TO_AK(in_pszTrigger), GameObjID );
  1834. }
  1835. return eResult;
  1836. }
  1837. AKRESULT FAkAudioDevice::PostTrigger(
  1838. const UAkTrigger* in_TriggerValue,
  1839. AActor* in_pActor
  1840. )
  1841. {
  1842. AkGameObjectID GameObjID = AK_INVALID_GAME_OBJECT;
  1843. AKRESULT eResult = GetGameObjectID(in_pActor, GameObjID);
  1844. if (m_bSoundEngineInitialized && in_TriggerValue && eResult == AK_Success)
  1845. {
  1846. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1847. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1848. eResult = SoundEngine->PostTrigger(in_TriggerValue->GetShortID(), GameObjID);
  1849. }
  1850. return eResult;
  1851. }
  1852. /**
  1853. * Set a RTPC in ak soundengine
  1854. *
  1855. * @param in_pszRtpcName Name of the RTPC
  1856. * @param in_value Value to set
  1857. * @param in_pActor Actor on which to set the RTPC
  1858. * @return Result from ak sound engine
  1859. */
  1860. AKRESULT FAkAudioDevice::SetRTPCValue(
  1861. const TCHAR * in_pszRtpcName,
  1862. AkRtpcValue in_value,
  1863. int32 in_interpolationTimeMs = 0,
  1864. AActor * in_pActor = NULL
  1865. )
  1866. {
  1867. AKRESULT eResult = AK_Success;
  1868. if (m_bSoundEngineInitialized)
  1869. {
  1870. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1871. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1872. auto RtpcID = SoundEngine->GetIDFromString(TCHAR_TO_AK(in_pszRtpcName));
  1873. eResult = SetRTPCValue(RtpcID, in_value, in_interpolationTimeMs, in_pActor);
  1874. }
  1875. return eResult;
  1876. }
  1877. /**
  1878. * Set a RTPC in ak soundengine
  1879. *
  1880. * @param in_Rtpc RTPC Short ID
  1881. * @param in_value Value to set
  1882. * @param in_interpolationTimeMs - Duration during which the RTPC is interpolated towards in_value (in ms)
  1883. * @param in_pActor AActor on which to set the RTPC
  1884. * @return Result from ak sound engine
  1885. */
  1886. AKRESULT FAkAudioDevice::SetRTPCValue(
  1887. AkRtpcID in_Rtpc,
  1888. AkRtpcValue in_value,
  1889. int32 in_interpolationTimeMs = 0,
  1890. AActor * in_pActor = NULL
  1891. )
  1892. {
  1893. AKRESULT eResult = AK_Success;
  1894. if (m_bSoundEngineInitialized)
  1895. {
  1896. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1897. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1898. AkGameObjectID GameObjID = AK_INVALID_GAME_OBJECT; // RTPC at global scope is supported
  1899. if (in_pActor)
  1900. {
  1901. eResult = GetGameObjectID(in_pActor, GameObjID);
  1902. if (eResult != AK_Success)
  1903. return eResult;
  1904. }
  1905. eResult = SoundEngine->SetRTPCValue(in_Rtpc, in_value, GameObjID, in_interpolationTimeMs);
  1906. }
  1907. return eResult;
  1908. }
  1909. AKRESULT FAkAudioDevice::SetRTPCValue(
  1910. const UAkRtpc* in_RtpcValue,
  1911. AkRtpcValue in_value,
  1912. int32 in_interpolationTimeMs = 0,
  1913. AActor * in_pActor = NULL
  1914. )
  1915. {
  1916. AKRESULT eResult = AK_Success;
  1917. if (m_bSoundEngineInitialized && in_RtpcValue)
  1918. {
  1919. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1920. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1921. AkGameObjectID GameObjID = AK_INVALID_GAME_OBJECT; // RTPC at global scope is supported
  1922. if (in_pActor)
  1923. {
  1924. eResult = GetGameObjectID(in_pActor, GameObjID);
  1925. if (eResult != AK_Success)
  1926. return eResult;
  1927. }
  1928. eResult = SoundEngine->SetRTPCValue(in_RtpcValue->GetShortID(), in_value, GameObjID, in_interpolationTimeMs);
  1929. }
  1930. return eResult;
  1931. }
  1932. AKRESULT FAkAudioDevice::SetRTPCValueByPlayingID(
  1933. AkRtpcID in_Rtpc,
  1934. AkRtpcValue in_value,
  1935. AkPlayingID in_playingID,
  1936. int32 in_interpolationTimeMs
  1937. )
  1938. {
  1939. AKRESULT eResult = AK_Success;
  1940. if (m_bSoundEngineInitialized)
  1941. {
  1942. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1943. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1944. eResult = SoundEngine->SetRTPCValueByPlayingID(in_Rtpc, in_value, in_playingID, in_interpolationTimeMs);
  1945. }
  1946. return eResult;
  1947. }
  1948. /**
  1949. * Get the value of a real-time parameter control (by ID)
  1950. * An RTPC can have a any combination of a global value, a unique value for each game object, or a unique value for each playing ID.
  1951. * The value requested is determined by RTPCValue_type, in_gameObjectID and in_playingID.
  1952. * If a value at the requested scope (determined by RTPCValue_type) is not found, the value that is available at the the next broadest scope will be returned, and io_rValueType will be changed to indicate this.
  1953. * @note
  1954. * When looking up RTPC values via playing ID (ie. io_rValueType is RTPC_PlayingID), in_gameObjectID can be set to a specific game object (if it is available to the caller) to use as a fall back value.
  1955. * If the game object is unknown or unavailable, AK_INVALID_GAME_OBJECT can be passed in in_gameObjectID, and the game object will be looked up via in_playingID.
  1956. * However in this case, it is not possible to retrieve a game object value as a fall back value if the playing id does not exist. It is best to pass in the game object if possible.
  1957. *
  1958. * @return AK_Success if succeeded, AK_IDNotFound if the game object was not registered, or AK_Fail if the RTPC value could not be obtained
  1959. */
  1960. AKRESULT FAkAudioDevice::GetRTPCValue(
  1961. const TCHAR * in_pszRtpcName,
  1962. AkGameObjectID in_gameObjectID, ///< Associated game object ID, ignored if io_rValueType is RTPCValue_Global.
  1963. AkPlayingID in_playingID, ///< Associated playing ID, ignored if io_rValueType is not RTPC_PlayingID.
  1964. AkRtpcValue& out_rValue, ///< Value returned
  1965. AK::SoundEngine::Query::RTPCValue_type& io_rValueType ///< In/Out value, the user must specify the requested type. The function will return in this variable the type of the returned value. );
  1966. )
  1967. {
  1968. AKRESULT eResult = AK_Success;
  1969. if (m_bSoundEngineInitialized)
  1970. {
  1971. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  1972. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  1973. eResult = SoundEngine->Query->GetRTPCValue(TCHAR_TO_AK(in_pszRtpcName), in_gameObjectID, in_playingID, out_rValue, io_rValueType);
  1974. }
  1975. return eResult;
  1976. }
  1977. /**
  1978. * Get the value of a real-time parameter control (by ID)
  1979. * An RTPC can have a any combination of a global value, a unique value for each game object, or a unique value for each playing ID.
  1980. * The value requested is determined by RTPCValue_type, in_gameObjectID and in_playingID.
  1981. * If a value at the requested scope (determined by RTPCValue_type) is not found, the value that is available at the the next broadest scope will be returned, and io_rValueType will be changed to indicate this.
  1982. * @note
  1983. * When looking up RTPC values via playing ID (ie. io_rValueType is RTPC_PlayingID), in_gameObjectID can be set to a specific game object (if it is available to the caller) to use as a fall back value.
  1984. * If the game object is unknown or unavailable, AK_INVALID_GAME_OBJECT can be passed in in_gameObjectID, and the game object will be looked up via in_playingID.
  1985. * However in this case, it is not possible to retrieve a game object value as a fall back value if the playing id does not exist. It is best to pass in the game object if possible.
  1986. *
  1987. * @return AK_Success if succeeded, AK_IDNotFound if the game object was not registered, or AK_Fail if the RTPC value could not be obtained
  1988. */
  1989. AKRESULT FAkAudioDevice::GetRTPCValue(
  1990. AkRtpcID in_Rtpc,
  1991. AkGameObjectID in_gameObjectID, ///< Associated game object ID, ignored if io_rValueType is RTPCValue_Global.
  1992. AkPlayingID in_playingID, ///< Associated playing ID, ignored if io_rValueType is not RTPC_PlayingID.
  1993. AkRtpcValue& out_rValue, ///< Value returned
  1994. AK::SoundEngine::Query::RTPCValue_type& io_rValueType ///< In/Out value, the user must specify the requested type. The function will return in this variable the type of the returned value. );
  1995. )
  1996. {
  1997. AKRESULT eResult = AK_Success;
  1998. if (m_bSoundEngineInitialized)
  1999. {
  2000. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2001. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2002. eResult = SoundEngine->Query->GetRTPCValue(in_Rtpc, in_gameObjectID, in_playingID, out_rValue, io_rValueType);
  2003. }
  2004. return eResult;
  2005. }
  2006. AKRESULT FAkAudioDevice::GetRTPCValue(
  2007. const UAkRtpc* in_RtpcValue,
  2008. AkGameObjectID in_gameObjectID, ///< Associated game object ID, ignored if io_rValueType is RTPCValue_Global.
  2009. AkPlayingID in_playingID, ///< Associated playing ID, ignored if io_rValueType is not RTPC_PlayingID.
  2010. AkRtpcValue& out_rValue, ///< Value returned
  2011. AK::SoundEngine::Query::RTPCValue_type& io_rValueType ///< In/Out value, the user must specify the requested type. The function will return in this variable the type of the returned value. );
  2012. )
  2013. {
  2014. AKRESULT eResult = AK_Success;
  2015. if (m_bSoundEngineInitialized && in_RtpcValue)
  2016. {
  2017. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2018. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2019. eResult = SoundEngine->Query->GetRTPCValue(in_RtpcValue->GetShortID(), in_gameObjectID, in_playingID, out_rValue, io_rValueType);
  2020. }
  2021. return eResult;
  2022. }
  2023. AKRESULT FAkAudioDevice::ResetRTPCValue(const UAkRtpc* in_RtpcValue, AkGameObjectID in_gameObjectID, int32 in_interpolationTimeMs)
  2024. {
  2025. AKRESULT eResult = AK_Success;
  2026. if (m_bSoundEngineInitialized && in_RtpcValue)
  2027. {
  2028. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2029. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2030. eResult = SoundEngine->ResetRTPCValue(in_RtpcValue->GetShortID(), in_gameObjectID, in_interpolationTimeMs);
  2031. }
  2032. return eResult;
  2033. }
  2034. AKRESULT FAkAudioDevice::ResetRTPCValue(AkRtpcID in_rtpcID, AkGameObjectID in_gameObjectID, int32 in_interpolationTimeMs)
  2035. {
  2036. AKRESULT eResult = AK_Success;
  2037. if (m_bSoundEngineInitialized && in_rtpcID)
  2038. {
  2039. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2040. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2041. eResult = SoundEngine->ResetRTPCValue(in_rtpcID, in_gameObjectID, in_interpolationTimeMs);
  2042. }
  2043. return eResult;
  2044. }
  2045. AKRESULT FAkAudioDevice::ResetRTPCValue(const TCHAR* in_pszRtpcName, AkGameObjectID in_gameObjectID, int32 in_interpolationTimeMs)
  2046. {
  2047. AKRESULT eResult = AK_Success;
  2048. if (m_bSoundEngineInitialized)
  2049. {
  2050. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2051. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2052. eResult = SoundEngine->ResetRTPCValue(TCHAR_TO_AK(in_pszRtpcName), in_gameObjectID, in_interpolationTimeMs);
  2053. }
  2054. return eResult;
  2055. }
  2056. /**
  2057. * Set a state in ak soundengine
  2058. *
  2059. * @param in_pszStateGroup Name of the state group
  2060. * @param in_pszState Name of the state
  2061. * @return Result from ak sound engine
  2062. */
  2063. AKRESULT FAkAudioDevice::SetState(
  2064. const TCHAR * in_pszStateGroup,
  2065. const TCHAR * in_pszState
  2066. )
  2067. {
  2068. AKRESULT eResult = AK_Success;
  2069. if ( m_bSoundEngineInitialized )
  2070. {
  2071. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2072. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2073. auto StateGroupID = SoundEngine->GetIDFromString(TCHAR_TO_AK(in_pszStateGroup));
  2074. auto StateID = SoundEngine->GetIDFromString(TCHAR_TO_AK(in_pszState));
  2075. eResult = SoundEngine->SetState(StateGroupID, StateID);
  2076. }
  2077. return eResult;
  2078. }
  2079. /**
  2080. * Set a state in ak soundengine
  2081. *
  2082. * @param in_StateGroup State group short ID
  2083. * @param in_State State short ID
  2084. * @return Result from ak sound engine
  2085. */
  2086. AKRESULT FAkAudioDevice::SetState(
  2087. AkStateGroupID in_StateGroup,
  2088. AkStateID in_State
  2089. )
  2090. {
  2091. AKRESULT eResult = AK_Success;
  2092. if ( m_bSoundEngineInitialized )
  2093. {
  2094. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2095. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2096. eResult = SoundEngine->SetState(in_StateGroup, in_State);
  2097. }
  2098. return eResult;
  2099. }
  2100. AKRESULT FAkAudioDevice::SetState(
  2101. const UAkStateValue* in_stateValue
  2102. )
  2103. {
  2104. AKRESULT eResult = AK_Success;
  2105. if (m_bSoundEngineInitialized && in_stateValue)
  2106. {
  2107. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2108. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2109. eResult = SoundEngine->SetState(in_stateValue->GetGroupID(), in_stateValue->GetShortID());
  2110. }
  2111. return eResult;
  2112. }
  2113. /**
  2114. * Set a switch in ak soundengine
  2115. *
  2116. * @param in_pszSwitchGroup Name of the switch group
  2117. * @param in_pszSwitchState Name of the switch
  2118. * @param in_pComponent AkComponent on which to set the switch
  2119. * @return Result from ak sound engine
  2120. */
  2121. AKRESULT FAkAudioDevice::SetSwitch(
  2122. const TCHAR * in_pszSwitchGroup,
  2123. const TCHAR * in_pszSwitchState,
  2124. AActor * in_pActor
  2125. )
  2126. {
  2127. AKRESULT eResult = AK_Success;
  2128. if ( m_bSoundEngineInitialized)
  2129. {
  2130. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2131. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2132. auto SwitchGroupID = SoundEngine->GetIDFromString(TCHAR_TO_AK(in_pszSwitchGroup));
  2133. auto SwitchStateID = SoundEngine->GetIDFromString(TCHAR_TO_AK(in_pszSwitchState));
  2134. eResult = SetSwitch(SwitchGroupID, SwitchStateID, in_pActor);
  2135. }
  2136. return eResult;
  2137. }
  2138. /**
  2139. * Set a switch in ak soundengine
  2140. *
  2141. * @param in_SwitchGroup Short ID of the switch group
  2142. * @param in_SwitchState Short ID of the switch
  2143. * @param in_pComponent AkComponent on which to set the switch
  2144. * @return Result from ak sound engine
  2145. */
  2146. AKRESULT FAkAudioDevice::SetSwitch(
  2147. AkSwitchGroupID in_SwitchGroup,
  2148. AkSwitchStateID in_SwitchState,
  2149. AActor * in_pActor
  2150. )
  2151. {
  2152. AkGameObjectID GameObjID = DUMMY_GAMEOBJ;
  2153. // Switches must be bound to a game object. passing DUMMY_GAMEOBJ as default game object.
  2154. AKRESULT eResult = GetGameObjectID( in_pActor, GameObjID );
  2155. if ( m_bSoundEngineInitialized && eResult == AK_Success)
  2156. {
  2157. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2158. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2159. eResult = SoundEngine->SetSwitch(in_SwitchGroup, in_SwitchState, GameObjID);
  2160. }
  2161. return eResult;
  2162. }
  2163. AKRESULT FAkAudioDevice::SetSwitch(
  2164. const UAkSwitchValue* in_switchValue,
  2165. AActor * in_pActor
  2166. )
  2167. {
  2168. AkGameObjectID GameObjID = DUMMY_GAMEOBJ;
  2169. // Switches must be bound to a game object. passing DUMMY_GAMEOBJ as default game object.
  2170. AKRESULT eResult = GetGameObjectID(in_pActor, GameObjID);
  2171. if (m_bSoundEngineInitialized && in_switchValue && eResult == AK_Success)
  2172. {
  2173. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2174. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2175. eResult = SoundEngine->SetSwitch(in_switchValue->GetGroupID(), in_switchValue->GetShortID(), GameObjID);
  2176. }
  2177. return eResult;
  2178. }
  2179. static AK::SoundEngine::MultiPositionType GetSoundEngineMultiPositionType(AkMultiPositionType in_eType)
  2180. {
  2181. switch (in_eType)
  2182. {
  2183. case AkMultiPositionType::SingleSource: return AK::SoundEngine::MultiPositionType_SingleSource;
  2184. case AkMultiPositionType::MultiSources: return AK::SoundEngine::MultiPositionType_MultiSources;
  2185. case AkMultiPositionType::MultiDirections: return AK::SoundEngine::MultiPositionType_MultiDirections;
  2186. // Unknown multi position type!
  2187. default: check(false); return AK::SoundEngine::MultiPositionType_SingleSource;
  2188. }
  2189. }
  2190. /** Sets multiple positions to a single game object.
  2191. * Setting multiple positions on a single game object is a way to simulate multiple emission sources while using the resources of only one voice.
  2192. * This can be used to simulate wall openings, area sounds, or multiple objects emitting the same sound in the same area.
  2193. * Note: Calling AK::SoundEngine::SetMultiplePositions() with only one position is the same as calling AK::SoundEngine::SetPosition()
  2194. * @param in_pGameObjectAkComponent Game Object AkComponent.
  2195. * @param in_pPositions Array of positions to apply.
  2196. * @param in_eMultiPositionType Position type
  2197. * @return AK_Success when successful, AK_InvalidParameter if parameters are not valid.
  2198. *
  2199. */
  2200. AKRESULT FAkAudioDevice::SetMultiplePositions(
  2201. UAkComponent* in_pGameObjectAkComponent,
  2202. TArray<FTransform> in_aPositions,
  2203. AkMultiPositionType in_eMultiPositionType /*= AkMultiPositionType::MultiDirections*/
  2204. )
  2205. {
  2206. if (!in_pGameObjectAkComponent)
  2207. {
  2208. return AK_Fail;
  2209. }
  2210. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2211. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2212. const int numPositions = in_aPositions.Num();
  2213. TArray<AkSoundPosition> aPositions;
  2214. aPositions.Empty();
  2215. for (int i = 0; i < numPositions; ++i)
  2216. {
  2217. AkSoundPosition soundpos;
  2218. FAkAudioDevice::FVectorsToAKWorldTransform(in_aPositions[i].GetLocation(), in_aPositions[i].GetRotation().GetForwardVector(), in_aPositions[i].GetRotation().GetUpVector(), soundpos);
  2219. aPositions.Add(soundpos);
  2220. }
  2221. return SoundEngine->SetMultiplePositions(in_pGameObjectAkComponent->GetAkGameObjectID(), aPositions.GetData(),
  2222. aPositions.Num(), GetSoundEngineMultiPositionType(in_eMultiPositionType));
  2223. }
  2224. template<typename ChannelConfig>
  2225. AKRESULT FAkAudioDevice::SetMultiplePositions(
  2226. UAkComponent* in_pGameObjectAkComponent,
  2227. const TArray<ChannelConfig>& in_aChannelConfigurations,
  2228. const TArray<FTransform>& in_aPositions,
  2229. AkMultiPositionType in_eMultiPositionType /*= AkMultiPositionType::MultiDirections*/
  2230. )
  2231. {
  2232. if (!in_pGameObjectAkComponent)
  2233. {
  2234. return AK_Fail;
  2235. }
  2236. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2237. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2238. const int32 numPositions = FMath::Min(in_aPositions.Num(), in_aChannelConfigurations.Num());
  2239. TArray<AkChannelEmitter> emitters;
  2240. emitters.Reserve(numPositions);
  2241. for (int i = 0; i < numPositions; ++i)
  2242. {
  2243. AkSoundPosition soundpos;
  2244. FAkAudioDevice::FVectorsToAKWorldTransform(in_aPositions[i].GetLocation(), in_aPositions[i].GetRotation().GetForwardVector(), in_aPositions[i].GetRotation().GetUpVector(), soundpos);
  2245. AkChannelConfig config;
  2246. GetChannelConfig(in_aChannelConfigurations[i], config);
  2247. emitters.Add(AkChannelEmitter());
  2248. emitters[i].uInputChannels = config.uChannelMask;
  2249. emitters[i].position = soundpos;
  2250. }
  2251. return SoundEngine->SetMultiplePositions(in_pGameObjectAkComponent->GetAkGameObjectID(), emitters.GetData(),
  2252. emitters.Num(), GetSoundEngineMultiPositionType(in_eMultiPositionType));
  2253. }
  2254. AKRESULT FAkAudioDevice::SetMultiplePositions(
  2255. UAkComponent* in_pGameObjectAkComponent,
  2256. const TArray<AkChannelConfiguration>& in_aChannelConfigurations,
  2257. const TArray<FTransform>& in_aPositions,
  2258. AkMultiPositionType in_eMultiPositionType
  2259. )
  2260. {
  2261. return SetMultiplePositions<AkChannelConfiguration>(in_pGameObjectAkComponent, in_aChannelConfigurations, in_aPositions, in_eMultiPositionType);
  2262. }
  2263. AKRESULT FAkAudioDevice::SetMultiplePositions(
  2264. UAkComponent* in_pGameObjectAkComponent,
  2265. const TArray<FAkChannelMask>& in_channelMasks,
  2266. const TArray<FTransform>& in_aPositions,
  2267. AkMultiPositionType in_eMultiPositionType
  2268. )
  2269. {
  2270. return SetMultiplePositions<FAkChannelMask>(in_pGameObjectAkComponent, in_channelMasks, in_aPositions, in_eMultiPositionType);
  2271. }
  2272. /** Sets multiple positions to a single game object.
  2273. * Setting multiple positions on a single game object is a way to simulate multiple emission sources while using the resources of only one voice.
  2274. * This can be used to simulate wall openings, area sounds, or multiple objects emitting the same sound in the same area.
  2275. * Note: Calling AK::SoundEngine::SetMultiplePositions() with only one position is the same as calling AK::SoundEngine::SetPosition()
  2276. * @param in_GameObjectID Game Object identifier.
  2277. * @param in_pPositions Array of positions to apply.
  2278. * @param in_NumPositions Number of positions specified in the provided array.
  2279. * @param in_eMultiPositionType Position type
  2280. * @return AK_Success when successful, AK_InvalidParameter if parameters are not valid.
  2281. */
  2282. AKRESULT FAkAudioDevice::SetMultiplePositions(
  2283. AkGameObjectID in_GameObjectID,
  2284. const AkSoundPosition * in_pPositions,
  2285. AkUInt16 in_NumPositions,
  2286. AK::SoundEngine::MultiPositionType in_eMultiPositionType /*= AK::SoundEngine::MultiDirections*/
  2287. )
  2288. {
  2289. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2290. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2291. return SoundEngine->SetMultiplePositions(in_GameObjectID, in_pPositions, in_NumPositions, in_eMultiPositionType);
  2292. }
  2293. /** Sets multiple positions to a single game object, with flexible assignment of input channels.
  2294. * Setting multiple positions on a single game object is a way to simulate multiple emission sources while using the resources of only one voice.
  2295. * This can be used to simulate wall openings, area sounds, or multiple objects emitting the same sound in the same area.
  2296. * Note: Calling AK::SoundEngine::SetMultiplePositions() with only one position is the same as calling AK::SoundEngine::SetPosition()
  2297. * @param in_GameObjectID Game Object identifier.
  2298. * @param in_pPositions Array of positions to apply.
  2299. * @param in_NumPositions Number of positions specified in the provided array.
  2300. * @param in_eMultiPositionType Position type
  2301. * @return AK_Success when successful, AK_InvalidParameter if parameters are not valid.
  2302. */
  2303. AKRESULT FAkAudioDevice::SetMultiplePositions(
  2304. AkGameObjectID in_GameObjectID,
  2305. const AkChannelEmitter * in_pPositions,
  2306. AkUInt16 in_NumPositions,
  2307. AK::SoundEngine::MultiPositionType in_eMultiPositionType /*= AK::SoundEngine::MultiDirections*/
  2308. )
  2309. {
  2310. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2311. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2312. return SoundEngine->SetMultiplePositions(in_GameObjectID, in_pPositions, in_NumPositions, in_eMultiPositionType);
  2313. }
  2314. /**
  2315. * Set auxiliary sends
  2316. *
  2317. * @param in_GameObjId Wwise Game Object ID
  2318. * @param in_AuxSendValues Array of AkAuxSendValue, containins all Aux Sends to set on the game objectt
  2319. * @return Result from ak sound engine
  2320. */
  2321. AKRESULT FAkAudioDevice::SetAuxSends(
  2322. const UAkComponent* in_akComponent,
  2323. TArray<AkAuxSendValue>& in_AuxSendValues
  2324. )
  2325. {
  2326. AKRESULT eResult = AK_Success;
  2327. if ( m_bSoundEngineInitialized )
  2328. {
  2329. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2330. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2331. eResult = SoundEngine->SetGameObjectAuxSendValues(in_akComponent->GetAkGameObjectID(), in_AuxSendValues.GetData(), in_AuxSendValues.Num());
  2332. }
  2333. return eResult;
  2334. }
  2335. void FAkAudioDevice::GetChannelConfig(AkChannelConfiguration ChannelConfiguration, AkChannelConfig& config)
  2336. {
  2337. switch (ChannelConfiguration)
  2338. {
  2339. case AkChannelConfiguration::Ak_MainMix:
  2340. config.eConfigType = AK_ChannelConfigType_UseDeviceMain;
  2341. break;
  2342. case AkChannelConfiguration::Ak_Passthrough:
  2343. config.eConfigType = AK_ChannelConfigType_UseDevicePassthrough;
  2344. break;
  2345. case AkChannelConfiguration::Ak_LFE:
  2346. config.SetStandard(AK_SPEAKER_SETUP_0POINT1);
  2347. break;
  2348. case AkChannelConfiguration::AK_Audio_Objects:
  2349. config.SetObject();
  2350. break;
  2351. case AkChannelConfiguration::Ak_1_0:
  2352. config.SetStandard(AK_SPEAKER_SETUP_MONO);
  2353. break;
  2354. case AkChannelConfiguration::Ak_2_0:
  2355. config.SetStandard(AK_SPEAKER_SETUP_STEREO);
  2356. break;
  2357. case AkChannelConfiguration::Ak_2_1:
  2358. config.SetStandard(AK_SPEAKER_SETUP_2POINT1);
  2359. break;
  2360. case AkChannelConfiguration::Ak_3_0:
  2361. config.SetStandard(AK_SPEAKER_SETUP_3STEREO);
  2362. break;
  2363. case AkChannelConfiguration::Ak_3_1:
  2364. config.SetStandard(AK_SPEAKER_SETUP_3POINT1);
  2365. break;
  2366. case AkChannelConfiguration::Ak_4_0:
  2367. config.SetStandard(AK_SPEAKER_SETUP_4);
  2368. break;
  2369. case AkChannelConfiguration::Ak_4_1:
  2370. config.SetStandard(AK_SPEAKER_SETUP_4POINT1);
  2371. break;
  2372. case AkChannelConfiguration::Ak_5_0:
  2373. config.SetStandard(AK_SPEAKER_SETUP_5);
  2374. break;
  2375. case AkChannelConfiguration::Ak_5_1:
  2376. config.SetStandard(AK_SPEAKER_SETUP_5POINT1);
  2377. break;
  2378. case AkChannelConfiguration::Ak_7_1:
  2379. config.SetStandard(AK_SPEAKER_SETUP_7POINT1);
  2380. break;
  2381. case AkChannelConfiguration::Ak_5_1_2:
  2382. config.SetStandard(AK_SPEAKER_SETUP_DOLBY_5_1_2);
  2383. break;
  2384. case AkChannelConfiguration::Ak_7_1_2:
  2385. config.SetStandard(AK_SPEAKER_SETUP_DOLBY_7_1_2);
  2386. break;
  2387. case AkChannelConfiguration::Ak_7_1_4:
  2388. config.SetStandard(AK_SPEAKER_SETUP_DOLBY_7_1_4);
  2389. break;
  2390. case AkChannelConfiguration::Ak_Auro_9_1:
  2391. config.SetStandard(AK_SPEAKER_SETUP_AURO_9POINT1);
  2392. break;
  2393. case AkChannelConfiguration::Ak_Auro_10_1:
  2394. config.SetStandard(AK_SPEAKER_SETUP_AURO_10POINT1);
  2395. break;
  2396. case AkChannelConfiguration::Ak_Auro_11_1:
  2397. config.SetStandard(AK_SPEAKER_SETUP_AURO_11POINT1);
  2398. break;
  2399. case AkChannelConfiguration::Ak_Auro_13_1:
  2400. config.SetStandard(AK_SPEAKER_SETUP_AURO_13POINT1_751);
  2401. break;
  2402. case AkChannelConfiguration::Ak_Ambisonics_1st_order:
  2403. config.SetAmbisonic(4);
  2404. break;
  2405. case AkChannelConfiguration::Ak_Ambisonics_2nd_order:
  2406. config.SetAmbisonic(9);
  2407. break;
  2408. case AkChannelConfiguration::Ak_Ambisonics_3rd_order:
  2409. config.SetAmbisonic(16);
  2410. break;
  2411. case AkChannelConfiguration::Ak_Ambisonics_4th_order:
  2412. config.SetAmbisonic(25);
  2413. break;
  2414. case AkChannelConfiguration::Ak_Ambisonics_5th_order:
  2415. config.SetAmbisonic(36);
  2416. break;
  2417. case AkChannelConfiguration::Ak_Parent:
  2418. default:
  2419. config.Clear();
  2420. break;
  2421. }
  2422. }
  2423. void FAkAudioDevice::GetChannelConfig(FAkChannelMask SpeakerConfig, AkChannelConfig& config)
  2424. {
  2425. config.SetStandard(SpeakerConfig.ChannelMask);
  2426. }
  2427. /**
  2428. * Set spatial audio room
  2429. *
  2430. * @param in_GameObjId Wwise Game Object ID
  2431. * @param in_RoomID ID of the room that the game object is inside.
  2432. * @return Result from ak sound engine
  2433. */
  2434. AKRESULT FAkAudioDevice::SetInSpatialAudioRoom(
  2435. const AkGameObjectID in_GameObjId,
  2436. AkRoomID in_RoomID
  2437. )
  2438. {
  2439. AKRESULT eResult = AK_Success;
  2440. #ifdef AK_ENABLE_ROOMS
  2441. if (m_bSoundEngineInitialized)
  2442. {
  2443. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2444. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2445. eResult = SpatialAudio->SetGameObjectInRoom(in_GameObjId, in_RoomID);
  2446. }
  2447. #endif
  2448. return eResult;
  2449. }
  2450. AKRESULT FAkAudioDevice::SetBusConfig(
  2451. const FString& in_BusName,
  2452. AkChannelConfig in_Config
  2453. )
  2454. {
  2455. AKRESULT eResult = AK_Fail;
  2456. if (in_BusName.IsEmpty())
  2457. {
  2458. return eResult;
  2459. }
  2460. if (m_bSoundEngineInitialized)
  2461. {
  2462. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2463. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2464. AkUniqueID BusId = GetShortIDFromString(in_BusName);
  2465. eResult = SoundEngine->SetBusConfig(BusId, in_Config);
  2466. }
  2467. return eResult;
  2468. }
  2469. AKRESULT FAkAudioDevice::SetPanningRule(
  2470. AkPanningRule in_ePanningRule
  2471. )
  2472. {
  2473. AKRESULT eResult = AK_Fail;
  2474. if (m_bSoundEngineInitialized)
  2475. {
  2476. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2477. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2478. eResult = SoundEngine->SetPanningRule(in_ePanningRule);
  2479. }
  2480. return eResult;
  2481. }
  2482. AkOutputDeviceID FAkAudioDevice::GetOutputID(
  2483. const FString& in_szShareSet,
  2484. AkUInt32 in_idDevice
  2485. )
  2486. {
  2487. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2488. if (UNLIKELY(!SoundEngine)) return AK_INVALID_OUTPUT_DEVICE_ID;
  2489. return SoundEngine->GetOutputID(TCHAR_TO_AK(*in_szShareSet), in_idDevice);
  2490. }
  2491. AKRESULT FAkAudioDevice::ReplaceMainOutput(const AkOutputSettings& MainOutputSettings)
  2492. {
  2493. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2494. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2495. AKRESULT Result = SoundEngine->ReplaceOutput(MainOutputSettings, 0);
  2496. SoundEngine->RenderAudio();
  2497. return Result;
  2498. }
  2499. AKRESULT FAkAudioDevice::GetSpeakerAngles(
  2500. TArray<AkReal32>& out_pfSpeakerAngles,
  2501. AkReal32& out_fHeightAngle,
  2502. AkOutputDeviceID in_idOutput
  2503. )
  2504. {
  2505. AKRESULT eResult = AK_Fail;
  2506. if (m_bSoundEngineInitialized)
  2507. {
  2508. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2509. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2510. AkUInt32 numSpeakers;
  2511. // Retrieve the number of speaker and height angle
  2512. eResult = SoundEngine->GetSpeakerAngles(NULL, numSpeakers, out_fHeightAngle);
  2513. if (eResult != AK_Success)
  2514. return eResult;
  2515. // Retrieve the speaker angles
  2516. out_pfSpeakerAngles.SetNum(numSpeakers);
  2517. eResult = SoundEngine->GetSpeakerAngles(out_pfSpeakerAngles.GetData(), numSpeakers, out_fHeightAngle, in_idOutput);
  2518. }
  2519. return eResult;
  2520. }
  2521. AKRESULT FAkAudioDevice::SetSpeakerAngles(
  2522. const TArray<AkReal32>& in_pfSpeakerAngles,
  2523. AkReal32 in_fHeightAngle,
  2524. AkOutputDeviceID in_idOutput
  2525. )
  2526. {
  2527. AKRESULT eResult = AK_Fail;
  2528. if (m_bSoundEngineInitialized)
  2529. {
  2530. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2531. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2532. eResult = SoundEngine->SetSpeakerAngles(in_pfSpeakerAngles.GetData(), in_pfSpeakerAngles.Num(), in_fHeightAngle, in_idOutput);
  2533. }
  2534. return eResult;
  2535. }
  2536. AKRESULT FAkAudioDevice::SetGameObjectOutputBusVolume(
  2537. const UAkComponent* in_pEmitter,
  2538. const UAkComponent* in_pListener,
  2539. float in_fControlValue
  2540. )
  2541. {
  2542. AKRESULT eResult = AK_Success;
  2543. if (m_bSoundEngineInitialized)
  2544. {
  2545. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2546. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2547. const AkGameObjectID emitterId = in_pEmitter ? in_pEmitter->GetAkGameObjectID() : DUMMY_GAMEOBJ;
  2548. const AkGameObjectID listenerId = in_pListener ? in_pListener->GetAkGameObjectID() : DUMMY_GAMEOBJ;
  2549. eResult = SoundEngine->SetGameObjectOutputBusVolume(emitterId, listenerId, in_fControlValue);
  2550. }
  2551. return eResult;
  2552. }
  2553. /**
  2554. * Obtain a pointer to the singleton instance of FAkAudioDevice
  2555. *
  2556. * @return Pointer to the singleton instance of FAkAudioDevice
  2557. */
  2558. FAkAudioDevice * FAkAudioDevice::Get()
  2559. {
  2560. if (UNLIKELY(m_EngineExiting))
  2561. {
  2562. return nullptr;
  2563. }
  2564. if (LIKELY(FAkAudioModule::AkAudioModuleInstance))
  2565. {
  2566. return FAkAudioModule::AkAudioModuleInstance->GetAkAudioDevice();
  2567. }
  2568. else
  2569. {
  2570. FAkAudioModule* ModulePtr = FModuleManager::LoadModulePtr<FAkAudioModule>(TEXT("AkAudio"));
  2571. UE_CLOG(!ModulePtr, LogAkAudio, Warning, TEXT("No AkAudio module"));
  2572. UE_CLOG(FAkAudioModule::AkAudioModuleInstance != ModulePtr, LogAkAudio, Warning, TEXT("AkAudio instance (%p) differs from loaded module (%p)."), FAkAudioModule::AkAudioModuleInstance, ModulePtr);
  2573. return ModulePtr ? ModulePtr->GetAkAudioDevice() : nullptr;
  2574. }
  2575. }
  2576. /**
  2577. * Gets the system sample rate
  2578. *
  2579. * @return Sample rate
  2580. */
  2581. AkUInt32 FAkAudioDevice::GetSampleRate()
  2582. {
  2583. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2584. if (UNLIKELY(!SoundEngine)) return 0;
  2585. return m_bSoundEngineInitialized ? SoundEngine->GetSampleRate() : 0;
  2586. }
  2587. /**
  2588. * Enables/disables offline rendering
  2589. *
  2590. * @param bEnable Set to true to enable offline rendering
  2591. */
  2592. AKRESULT FAkAudioDevice::SetOfflineRendering(bool bEnable)
  2593. {
  2594. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2595. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2596. return m_bSoundEngineInitialized ? SoundEngine->SetOfflineRendering(bEnable) : AK_Fail;
  2597. }
  2598. /**
  2599. * Sets the offline rendering frame time in seconds.
  2600. *
  2601. * @param FrameTimeInSeconds Frame time in seconds used during offline rendering
  2602. */
  2603. AKRESULT FAkAudioDevice::SetOfflineRenderingFrameTime(AkReal32 FrameTimeInSeconds)
  2604. {
  2605. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2606. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2607. return m_bSoundEngineInitialized ? SoundEngine->SetOfflineRenderingFrameTime(FrameTimeInSeconds) : AK_Fail;
  2608. }
  2609. /**
  2610. * Registers a callback used for retrieving audio samples.
  2611. *
  2612. * @param Callback Capture callback function to register
  2613. * @param OutputId The audio device specific id, return by AK::SoundEngine::AddOutput or AK::SoundEngine::GetOutputID
  2614. * @param Cookie Callback cookie that will be sent to the callback function along with additional information
  2615. */
  2616. AKRESULT FAkAudioDevice::RegisterCaptureCallback(AkCaptureCallbackFunc Callback, AkOutputDeviceID OutputId /*= AK_INVALID_OUTPUT_DEVICE_ID*/, void* Cookie /*= nullptr*/)
  2617. {
  2618. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2619. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2620. return m_bSoundEngineInitialized ? SoundEngine->RegisterCaptureCallback(Callback, OutputId, Cookie) : AK_Fail;
  2621. }
  2622. /**
  2623. * Unregisters a callback used for retrieving audio samples.
  2624. *
  2625. * @param Callback Capture callback function to register
  2626. * @param OutputId The audio device specific id, return by AK::SoundEngine::AddOutput or AK::SoundEngine::GetOutputID
  2627. * @param Cookie Callback cookie that will be sent to the callback function along with additional information
  2628. */
  2629. AKRESULT FAkAudioDevice::UnregisterCaptureCallback(AkCaptureCallbackFunc Callback, AkOutputDeviceID OutputId /*= AK_INVALID_OUTPUT_DEVICE_ID*/, void* Cookie /*= nullptr*/)
  2630. {
  2631. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2632. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2633. return m_bSoundEngineInitialized ? SoundEngine->UnregisterCaptureCallback(Callback, OutputId, Cookie) : AK_Fail;
  2634. }
  2635. /**
  2636. * Stop all audio associated with a game object
  2637. *
  2638. * @param in_GameObjID ID of the game object
  2639. */
  2640. void FAkAudioDevice::StopGameObject( UAkComponent * in_pComponent )
  2641. {
  2642. AkGameObjectID gameObjId = DUMMY_GAMEOBJ;
  2643. if ( in_pComponent )
  2644. {
  2645. gameObjId = in_pComponent->GetAkGameObjectID();
  2646. }
  2647. if ( m_bSoundEngineInitialized )
  2648. {
  2649. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2650. if (UNLIKELY(!SoundEngine)) return;
  2651. SoundEngine->StopAll( gameObjId );
  2652. }
  2653. }
  2654. /**
  2655. * Stop all audio associated with a playing ID
  2656. *
  2657. * @param in_playingID Playing ID to stop
  2658. * @param in_uTransitionDuration Fade duration
  2659. * @param in_eFadeCurve Curve type to be used for the transition
  2660. */
  2661. void FAkAudioDevice::StopPlayingID( AkPlayingID in_playingID,
  2662. AkTimeMs in_uTransitionDuration /*= 0*/,
  2663. AkCurveInterpolation in_eFadeCurve /*= AkCurveInterpolation_Linear*/)
  2664. {
  2665. if ( m_bSoundEngineInitialized )
  2666. {
  2667. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2668. if (UNLIKELY(!SoundEngine)) return;
  2669. SoundEngine->ExecuteActionOnPlayingID(AK::SoundEngine::AkActionOnEventType_Stop, in_playingID, in_uTransitionDuration, in_eFadeCurve );
  2670. }
  2671. }
  2672. /**
  2673. * Register an ak audio component with ak sound engine
  2674. *
  2675. * @param in_pComponent Pointer to the component to register
  2676. */
  2677. void FAkAudioDevice::RegisterComponent( UAkComponent * in_pComponent )
  2678. {
  2679. if (m_bSoundEngineInitialized && in_pComponent)
  2680. {
  2681. FString WwiseGameObjectName = TEXT("");
  2682. in_pComponent->GetAkGameObjectName(WwiseGameObjectName);
  2683. const AkGameObjectID gameObjId = in_pComponent->GetAkGameObjectID();
  2684. FAkAudioDevice_Helpers::RegisterGameObject(gameObjId, WwiseGameObjectName);
  2685. if (CallbackManager != nullptr)
  2686. CallbackManager->RegisterGameObject(gameObjId);
  2687. }
  2688. }
  2689. /**
  2690. * Register a game object with ak sound engine
  2691. *
  2692. * @param GameObjectID ID of the game object to register
  2693. */
  2694. void FAkAudioDevice::RegisterComponent(AkGameObjectID GameObjectID)
  2695. {
  2696. if (m_bSoundEngineInitialized && GameObjectID)
  2697. {
  2698. FAkAudioDevice_Helpers::RegisterGameObject(GameObjectID, "");
  2699. if (CallbackManager != nullptr)
  2700. CallbackManager->RegisterGameObject(GameObjectID);
  2701. }
  2702. }
  2703. /**
  2704. * Unregister an ak audio component with ak sound engine
  2705. *
  2706. * @param in_pComponent Pointer to the component to unregister
  2707. */
  2708. void FAkAudioDevice::UnregisterComponent( UAkComponent * in_pComponent )
  2709. {
  2710. if (m_bSoundEngineInitialized && in_pComponent)
  2711. {
  2712. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2713. if (LIKELY(SoundEngine))
  2714. {
  2715. const AkGameObjectID gameObjId = in_pComponent->GetAkGameObjectID();
  2716. SoundEngine->UnregisterGameObj(gameObjId);
  2717. if (CallbackManager != nullptr)
  2718. {
  2719. CallbackManager->UnregisterGameObject(gameObjId);
  2720. }
  2721. }
  2722. }
  2723. if (m_defaultListeners.Contains(in_pComponent))
  2724. {
  2725. RemoveDefaultListener(in_pComponent);
  2726. }
  2727. check(!m_defaultListeners.Contains(in_pComponent));
  2728. if (m_SpatialAudioListener == in_pComponent)
  2729. m_SpatialAudioListener = nullptr;
  2730. }
  2731. void FAkAudioDevice::UnregisterComponent( AkGameObjectID GameObjectId )
  2732. {
  2733. if (m_bSoundEngineInitialized && GameObjectId)
  2734. {
  2735. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2736. if (LIKELY(SoundEngine))
  2737. {
  2738. SoundEngine->UnregisterGameObj(GameObjectId);
  2739. }
  2740. if (CallbackManager != nullptr)
  2741. {
  2742. CallbackManager->UnregisterGameObject(GameObjectId);
  2743. }
  2744. }
  2745. }
  2746. AKRESULT FAkAudioDevice::SetGeometry(AkGeometrySetID GeometrySetID, const AkGeometryParams& Params)
  2747. {
  2748. AKRESULT eResult = AK_Fail;
  2749. if (m_bSoundEngineInitialized)
  2750. {
  2751. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2752. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2753. eResult = SpatialAudio->SetGeometry(GeometrySetID, Params);
  2754. }
  2755. return eResult;
  2756. }
  2757. AKRESULT FAkAudioDevice::SetGeometryInstance(AkGeometryInstanceID GeometryInstanceID, const AkGeometryInstanceParams& Params)
  2758. {
  2759. AKRESULT eResult = AK_Fail;
  2760. if (m_bSoundEngineInitialized)
  2761. {
  2762. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2763. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2764. eResult = SpatialAudio->SetGeometryInstance(GeometryInstanceID, Params);
  2765. }
  2766. return eResult;
  2767. }
  2768. AKRESULT FAkAudioDevice::RemoveGeometrySet(AkGeometrySetID GeometrySetID)
  2769. {
  2770. AKRESULT eResult = AK_Fail;
  2771. if (m_bSoundEngineInitialized)
  2772. {
  2773. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2774. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2775. eResult = SpatialAudio->RemoveGeometry(GeometrySetID);
  2776. }
  2777. return eResult;
  2778. }
  2779. AKRESULT FAkAudioDevice::RemoveGeometryInstance(AkGeometryInstanceID GeometryInstanceID)
  2780. {
  2781. AKRESULT eResult = AK_Fail;
  2782. if (m_bSoundEngineInitialized)
  2783. {
  2784. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2785. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2786. eResult = SpatialAudio->RemoveGeometryInstance(GeometryInstanceID);
  2787. }
  2788. return eResult;
  2789. }
  2790. AKRESULT FAkAudioDevice::SetEarlyReflectionsAuxBus(UAkComponent* in_pComponent, const AkUInt32 AuxBusID)
  2791. {
  2792. AKRESULT eResult = AK_Fail;
  2793. if (m_bSoundEngineInitialized && in_pComponent)
  2794. {
  2795. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2796. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2797. const AkGameObjectID gameObjId = in_pComponent->GetAkGameObjectID();
  2798. eResult = SpatialAudio->SetEarlyReflectionsAuxSend(gameObjId, AuxBusID);
  2799. }
  2800. return eResult;
  2801. }
  2802. AKRESULT FAkAudioDevice::SetEarlyReflectionsVolume(UAkComponent* in_pComponent, float in_fSendVolume)
  2803. {
  2804. AKRESULT eResult = AK_Fail;
  2805. if (m_bSoundEngineInitialized && in_pComponent)
  2806. {
  2807. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2808. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2809. const AkGameObjectID gameObjId = in_pComponent->GetAkGameObjectID();
  2810. eResult = SpatialAudio->SetEarlyReflectionsVolume(gameObjId, in_fSendVolume);
  2811. }
  2812. return eResult;
  2813. }
  2814. AKRESULT FAkAudioDevice::SetReflectionsOrder(int Order, bool RefreshPaths)
  2815. {
  2816. AKRESULT eResult = AK_Fail;
  2817. if (m_bSoundEngineInitialized)
  2818. {
  2819. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2820. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2821. eResult = SpatialAudio->SetReflectionsOrder(Order, RefreshPaths);
  2822. }
  2823. return eResult;
  2824. }
  2825. AKRESULT FAkAudioDevice::SetMultipleObstructionAndOcclusion(AkGameObjectID in_Object, AkGameObjectID in_listener, AkObstructionOcclusionValues* ObstructionAndOcclusionValues, AkUInt32 in_uNumObstructionAndOcclusion)
  2826. {
  2827. AKRESULT eResult = AK_Fail;
  2828. if(m_bSoundEngineInitialized)
  2829. {
  2830. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2831. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2832. eResult = SoundEngine->SetMultipleObstructionAndOcclusion(in_Object, in_listener, ObstructionAndOcclusionValues, in_uNumObstructionAndOcclusion);
  2833. }
  2834. return eResult;
  2835. }
  2836. AKRESULT FAkAudioDevice::SetObjectObstructionAndOcclusion(AkGameObjectID in_Object, AkGameObjectID in_listener, AkReal32 Obstruction, AkReal32 Occlusion)
  2837. {
  2838. AKRESULT eResult = AK_Fail;
  2839. if (m_bSoundEngineInitialized)
  2840. {
  2841. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2842. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2843. eResult = SoundEngine->SetObjectObstructionAndOcclusion(in_Object, in_listener, Obstruction, Occlusion);
  2844. }
  2845. return eResult;
  2846. }
  2847. AKRESULT FAkAudioDevice::SetPortalObstructionAndOcclusion(const UAkPortalComponent* in_pPortal, float in_fObstructionValue, float in_fOcclusionValue)
  2848. {
  2849. AKRESULT eResult = AK_Fail;
  2850. if (m_bSoundEngineInitialized && in_pPortal)
  2851. {
  2852. auto World = in_pPortal->GetWorld();
  2853. if (World && ShouldNotifySoundEngine(World->WorldType))
  2854. {
  2855. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2856. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2857. const AkPortalID portalID = in_pPortal->GetPortalID();
  2858. eResult = SpatialAudio->SetPortalObstructionAndOcclusion(portalID, in_fObstructionValue, in_fOcclusionValue);
  2859. }
  2860. }
  2861. return eResult;
  2862. }
  2863. AKRESULT FAkAudioDevice::SetGameObjectToPortalObstruction(const UAkComponent* in_pComponent, const UAkPortalComponent* in_pPortal, float in_fObstructionValue)
  2864. {
  2865. AKRESULT eResult = AK_Fail;
  2866. if (m_bSoundEngineInitialized && in_pComponent && in_pPortal)
  2867. {
  2868. auto World = in_pComponent->GetWorld();
  2869. if (World && ShouldNotifySoundEngine(World->WorldType))
  2870. {
  2871. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2872. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2873. const AkGameObjectID gameObjId = in_pComponent->GetAkGameObjectID();
  2874. const AkPortalID portalID = in_pPortal->GetPortalID();
  2875. eResult = SpatialAudio->SetGameObjectToPortalObstruction(gameObjId, portalID, in_fObstructionValue);
  2876. }
  2877. }
  2878. return eResult;
  2879. }
  2880. AKRESULT FAkAudioDevice::SetPortalToPortalObstruction(const UAkPortalComponent* in_pPortal0, const UAkPortalComponent* in_pPortal1, float in_fObstructionValue)
  2881. {
  2882. AKRESULT eResult = AK_Fail;
  2883. if (m_bSoundEngineInitialized && in_pPortal0 && in_pPortal1)
  2884. {
  2885. auto World = in_pPortal0->GetWorld();
  2886. if (World && ShouldNotifySoundEngine(World->WorldType))
  2887. {
  2888. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2889. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2890. const AkPortalID portalID0 = in_pPortal0->GetPortalID();
  2891. const AkPortalID portalID1 = in_pPortal1->GetPortalID();
  2892. eResult = SpatialAudio->SetPortalToPortalObstruction(portalID0, portalID1, in_fObstructionValue);
  2893. }
  2894. }
  2895. return eResult;
  2896. }
  2897. void FAkAudioDevice::UpdateDefaultActiveListeners()
  2898. {
  2899. if (m_bSoundEngineInitialized)
  2900. {
  2901. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2902. if (UNLIKELY(!SoundEngine)) return;
  2903. auto NumDefaultListeners = m_defaultListeners.Num();
  2904. auto pListenerIds = (AkGameObjectID*)alloca(NumDefaultListeners * sizeof(AkGameObjectID));
  2905. int index = 0;
  2906. for (auto DefaultListenerIter = m_defaultListeners.CreateConstIterator(); DefaultListenerIter; ++DefaultListenerIter)
  2907. pListenerIds[index++] = (*DefaultListenerIter)->GetAkGameObjectID();
  2908. if (NumDefaultListeners > 0)
  2909. {
  2910. SoundEngine->SetDefaultListeners(pListenerIds, NumDefaultListeners);
  2911. }
  2912. }
  2913. }
  2914. AKRESULT FAkAudioDevice::SetPosition(UAkComponent* in_akComponent, const AkSoundPosition& in_SoundPosition)
  2915. {
  2916. if (m_bSoundEngineInitialized)
  2917. {
  2918. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  2919. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  2920. return SoundEngine->SetPosition(in_akComponent->GetAkGameObjectID(), in_SoundPosition);
  2921. }
  2922. return AK_Fail;
  2923. }
  2924. AKRESULT FAkAudioDevice::AddRoom(UAkRoomComponent* in_pRoom, const AkRoomParams& in_RoomParams)
  2925. {
  2926. if (ShouldNotifySoundEngine(in_pRoom->GetWorld()->WorldType))
  2927. {
  2928. AKRESULT result = AK_Fail;
  2929. if (m_bSoundEngineInitialized)
  2930. {
  2931. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2932. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2933. UAkLateReverbComponent* ReverbComp = in_pRoom->GetReverbComponent();
  2934. UE_CLOG(UNLIKELY(ReverbComp && ReverbComp->bEnable && in_RoomParams.ReverbAuxBus == AK_INVALID_AUX_ID), LogAkAudio, Warning, TEXT("Enabled Late Reverb component for room %s without an assigned Late Reverb Aux Bus"), *in_pRoom->GetRoomName());
  2935. result = SpatialAudio->SetRoom(in_pRoom->GetRoomID(), in_RoomParams, TCHAR_TO_ANSI(*in_pRoom->GetRoomName()));
  2936. if (result == AK_Success)
  2937. {
  2938. IndexRoom(in_pRoom);
  2939. PortalsNeedRoomUpdate(in_pRoom->GetWorld());
  2940. }
  2941. }
  2942. return result;
  2943. }
  2944. IndexRoom(in_pRoom);
  2945. PortalsNeedRoomUpdate(in_pRoom->GetWorld());
  2946. return AK_Success;
  2947. }
  2948. AKRESULT FAkAudioDevice::UpdateRoom(UAkRoomComponent* in_pRoom, const AkRoomParams& in_RoomParams)
  2949. {
  2950. if (ShouldNotifySoundEngine(in_pRoom->GetWorld()->WorldType))
  2951. {
  2952. AKRESULT result = AK_Fail;
  2953. if (m_bSoundEngineInitialized)
  2954. {
  2955. check(in_pRoom->HasBeenRegisteredWithWwise());
  2956. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2957. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2958. check(in_pRoom->HasBeenRegisteredWithWwise());
  2959. result = SpatialAudio->SetRoom(in_pRoom->GetRoomID(), in_RoomParams, TCHAR_TO_ANSI(*in_pRoom->GetRoomName()));
  2960. if (result == AK_Success)
  2961. PortalsNeedRoomUpdate(in_pRoom->GetWorld());
  2962. }
  2963. return result;
  2964. }
  2965. PortalsNeedRoomUpdate(in_pRoom->GetWorld());
  2966. return AK_Success;
  2967. }
  2968. AKRESULT FAkAudioDevice::RemoveRoom(UAkRoomComponent* in_pRoom)
  2969. {
  2970. if (ShouldNotifySoundEngine(in_pRoom->GetWorld()->WorldType))
  2971. {
  2972. AKRESULT result = AK_Fail;
  2973. if (m_bSoundEngineInitialized)
  2974. {
  2975. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2976. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2977. result = SpatialAudio->RemoveRoom(in_pRoom->GetRoomID());
  2978. if (result == AK_Success)
  2979. {
  2980. UnindexRoom(in_pRoom);
  2981. PortalsNeedRoomUpdate(in_pRoom->GetWorld());
  2982. }
  2983. }
  2984. return result;
  2985. }
  2986. UnindexRoom(in_pRoom);
  2987. PortalsNeedRoomUpdate(in_pRoom->GetWorld());
  2988. return AK_Success;
  2989. }
  2990. AKRESULT FAkAudioDevice::SetGameObjectRadius(UAkComponent* in_akComponent, float in_outerRadius, float in_innerRadius)
  2991. {
  2992. if (!m_bSoundEngineInitialized)
  2993. return AK_Fail;
  2994. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  2995. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  2996. return SpatialAudio->SetGameObjectRadius(AkGameObjectID(in_akComponent), in_outerRadius, in_innerRadius);
  2997. }
  2998. AKRESULT FAkAudioDevice::SetImageSource(AAkSpotReflector* in_pSpotReflector, const AkImageSourceSettings& in_ImageSourceInfo, AkUniqueID in_AuxBusID, UAkComponent* in_AkComponent)
  2999. {
  3000. if (m_bSoundEngineInitialized)
  3001. {
  3002. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  3003. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  3004. return SpatialAudio->SetImageSource(in_pSpotReflector->GetImageSourceID(), in_ImageSourceInfo, TCHAR_TO_ANSI(*in_pSpotReflector->GetSpotReflectorName()), in_AuxBusID, in_AkComponent->GetAkGameObjectID());
  3005. }
  3006. return AK_Fail;
  3007. }
  3008. AKRESULT FAkAudioDevice::RemoveImageSource(AAkSpotReflector* in_pSpotReflector, AkUniqueID in_AuxBusID, UAkComponent* in_AkComponent)
  3009. {
  3010. if (m_bSoundEngineInitialized)
  3011. {
  3012. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  3013. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  3014. return SpatialAudio->RemoveImageSource(in_pSpotReflector->GetImageSourceID(), in_AuxBusID, in_AkComponent->GetAkGameObjectID());
  3015. }
  3016. return AK_Fail;
  3017. }
  3018. AKRESULT FAkAudioDevice::ClearImageSources(AkUniqueID in_AuxBusID, UAkComponent* in_AkComponent)
  3019. {
  3020. if (m_bSoundEngineInitialized)
  3021. {
  3022. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  3023. if (UNLIKELY(!SpatialAudio)) return AK_NotInitialized;
  3024. return SpatialAudio->ClearImageSources(in_AuxBusID, in_AkComponent == NULL ? AK_INVALID_GAME_OBJECT : in_AkComponent->GetAkGameObjectID());
  3025. }
  3026. return AK_Fail;
  3027. }
  3028. void FAkAudioDevice::SetListeners(UAkComponent* in_pEmitter, const TArray<UAkComponent*>& in_listenerSet)
  3029. {
  3030. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3031. if (UNLIKELY(!SoundEngine)) return;
  3032. check(!in_pEmitter->UseDefaultListeners());
  3033. auto NumListeners = in_listenerSet.Num();
  3034. auto pListenerIds = (AkGameObjectID*)alloca(NumListeners * sizeof(AkGameObjectID));
  3035. int index = 0;
  3036. for (const auto& Listener : in_listenerSet)
  3037. pListenerIds[index++] = Listener->GetAkGameObjectID();
  3038. SoundEngine->SetListeners(in_pEmitter->GetAkGameObjectID(), pListenerIds, NumListeners);
  3039. }
  3040. bool FAkAudioDevice::SetSpatialAudioListener(UAkComponent* in_pListener)
  3041. {
  3042. #if WITH_EDITOR
  3043. if (in_pListener == EditorListener)
  3044. {
  3045. return false;
  3046. }
  3047. #endif
  3048. m_SpatialAudioListener = in_pListener;
  3049. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  3050. if (UNLIKELY(!SpatialAudio)) return false;
  3051. SpatialAudio->RegisterListener((AkGameObjectID)m_SpatialAudioListener);
  3052. return true;
  3053. }
  3054. UAkComponent* FAkAudioDevice::GetSpatialAudioListener() const
  3055. {
  3056. return m_SpatialAudioListener;
  3057. }
  3058. UAkComponent* FAkAudioDevice::GetAkComponent(class USceneComponent* AttachToComponent, FName AttachPointName, const FVector * Location, EAttachLocation::Type LocationType)
  3059. {
  3060. bool ComponentCreated;
  3061. return GetAkComponent(AttachToComponent, AttachPointName, Location, LocationType, ComponentCreated);
  3062. }
  3063. UAkComponent* FAkAudioDevice::GetAkComponent( class USceneComponent* AttachToComponent, FName AttachPointName, const FVector * Location, EAttachLocation::Type LocationType, bool& ComponentCreated )
  3064. {
  3065. if (!AttachToComponent)
  3066. {
  3067. return NULL;
  3068. }
  3069. UAkComponent* AkComponent = NULL;
  3070. FAttachmentTransformRules AttachRules = FAttachmentTransformRules::KeepRelativeTransform;
  3071. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3072. if (UNLIKELY(!SoundEngine)) return nullptr;
  3073. if( GEngine && SoundEngine->IsInitialized())
  3074. {
  3075. AActor * Actor = AttachToComponent->GetOwner();
  3076. if( Actor )
  3077. {
  3078. if( !IsValid(Actor) )
  3079. {
  3080. // Avoid creating component if we're trying to play a sound on an already destroyed actor.
  3081. return NULL;
  3082. }
  3083. TArray<UAkComponent*> AkComponents;
  3084. Actor->GetComponents(AkComponents);
  3085. for ( int32 CompIdx = 0; CompIdx < AkComponents.Num(); CompIdx++ )
  3086. {
  3087. UAkComponent* pCompI = AkComponents[CompIdx];
  3088. if ( pCompI && pCompI->IsRegistered() )
  3089. {
  3090. if ( AttachToComponent == pCompI )
  3091. {
  3092. return pCompI;
  3093. }
  3094. if ( AttachToComponent != pCompI->GetAttachParent()
  3095. || AttachPointName != pCompI->GetAttachSocketName() )
  3096. {
  3097. continue;
  3098. }
  3099. // If a location is requested, try to match location.
  3100. if ( Location )
  3101. {
  3102. if (LocationType == EAttachLocation::KeepWorldPosition)
  3103. {
  3104. AttachRules = FAttachmentTransformRules::KeepWorldTransform;
  3105. if ( !FVector::PointsAreSame(*Location, pCompI->GetComponentLocation()) )
  3106. continue;
  3107. }
  3108. else
  3109. {
  3110. AttachRules = FAttachmentTransformRules::KeepRelativeTransform;
  3111. auto RelLoc = pCompI->GetRelativeLocation();
  3112. if ( !FVector::PointsAreSame(*Location, RelLoc) )
  3113. continue;
  3114. }
  3115. }
  3116. // AkComponent found which exactly matches the attachment: reuse it.
  3117. ComponentCreated = false;
  3118. return pCompI;
  3119. }
  3120. }
  3121. }
  3122. else
  3123. {
  3124. // Try to find if there is an AkComponent attached to AttachToComponent (will be the case if AttachToComponent has no owner)
  3125. const TArray<USceneComponent*> AttachChildren = AttachToComponent->GetAttachChildren();
  3126. for(int32 CompIdx = 0; CompIdx < AttachChildren.Num(); CompIdx++)
  3127. {
  3128. UAkComponent* pCompI = Cast<UAkComponent>(AttachChildren[CompIdx]);
  3129. if ( pCompI && pCompI->IsRegistered() )
  3130. {
  3131. // There is an associated AkComponent to AttachToComponent, no need to add another one.
  3132. ComponentCreated = false;
  3133. return pCompI;
  3134. }
  3135. }
  3136. }
  3137. if ( AkComponent == NULL )
  3138. {
  3139. if( Actor )
  3140. {
  3141. AkComponent = NewObject<UAkComponent>(Actor);
  3142. }
  3143. else
  3144. {
  3145. AkComponent = NewObject<UAkComponent>();
  3146. }
  3147. }
  3148. ComponentCreated = true;
  3149. check( AkComponent );
  3150. if (Location)
  3151. {
  3152. if (LocationType == EAttachLocation::KeepWorldPosition)
  3153. {
  3154. AttachRules = FAttachmentTransformRules::KeepWorldTransform;
  3155. AkComponent->SetWorldLocation(*Location);
  3156. }
  3157. else
  3158. {
  3159. AttachRules = FAttachmentTransformRules::KeepRelativeTransform;
  3160. AkComponent->SetRelativeLocation(*Location);
  3161. }
  3162. }
  3163. AkComponent->RegisterComponentWithWorld(AttachToComponent->GetWorld());
  3164. AkComponent->AttachToComponent(AttachToComponent, AttachRules, AttachPointName);
  3165. }
  3166. return( AkComponent );
  3167. }
  3168. /**
  3169. * Cancel the callback cookie for a dispatched event
  3170. *
  3171. * @param in_cookie The cookie to cancel
  3172. */
  3173. void FAkAudioDevice::CancelEventCallbackCookie(void* in_cookie)
  3174. {
  3175. if (m_bSoundEngineInitialized)
  3176. {
  3177. CallbackManager->CancelEventCallback(in_cookie);
  3178. }
  3179. }
  3180. /**
  3181. * Cancel the callback cookie for a dispatched event
  3182. *
  3183. * @param in_cookie The cookie to cancel
  3184. */
  3185. void FAkAudioDevice::CancelEventCallbackDelegate(const FOnAkPostEventCallback& in_Delegate)
  3186. {
  3187. if (m_bSoundEngineInitialized)
  3188. {
  3189. CallbackManager->CancelEventCallback(in_Delegate);
  3190. }
  3191. }
  3192. AKRESULT FAkAudioDevice::SetAttenuationScalingFactor(AActor* Actor, float ScalingFactor)
  3193. {
  3194. AKRESULT eResult = AK_Fail;
  3195. if ( m_bSoundEngineInitialized )
  3196. {
  3197. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3198. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  3199. AkGameObjectID GameObjID = DUMMY_GAMEOBJ;
  3200. eResult = GetGameObjectID( Actor, GameObjID );
  3201. if( eResult == AK_Success )
  3202. {
  3203. eResult = SoundEngine->SetScalingFactor(GameObjID, ScalingFactor);
  3204. }
  3205. }
  3206. return eResult;
  3207. }
  3208. AKRESULT FAkAudioDevice::SetAttenuationScalingFactor(UAkComponent* AkComponent, float ScalingFactor)
  3209. {
  3210. AKRESULT eResult = AK_Fail;
  3211. if ( m_bSoundEngineInitialized && AkComponent)
  3212. {
  3213. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3214. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  3215. eResult = SoundEngine->SetScalingFactor(AkComponent->GetAkGameObjectID(), ScalingFactor);
  3216. }
  3217. return eResult;
  3218. }
  3219. AKRESULT FAkAudioDevice::SetDistanceProbe(UAkComponent* Listener, UAkComponent* DistanceProbe)
  3220. {
  3221. AKRESULT eResult = AK_Fail;
  3222. if (m_bSoundEngineInitialized && Listener)
  3223. {
  3224. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3225. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  3226. eResult = SoundEngine->SetDistanceProbe(Listener->GetAkGameObjectID(), DistanceProbe != nullptr ? DistanceProbe->GetAkGameObjectID() : AK_INVALID_GAME_OBJECT );
  3227. }
  3228. return eResult;
  3229. }
  3230. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  3231. AkErrorMessageTranslator* FAkAudioDevice::m_UnrealErrorTranslator;
  3232. #endif
  3233. AKRESULT FAkAudioDevice::RegisterGameObject(AkGameObjectID GameObjectID, const FString& Name)
  3234. {
  3235. return FAkAudioDevice_Helpers::RegisterGameObject(GameObjectID, Name);
  3236. }
  3237. bool FAkAudioDevice::EnsureInitialized()
  3238. {
  3239. static bool bPermanentInitializationFailure = false;
  3240. static bool bLogWwiseVersionOnce = true;
  3241. if (LIKELY(m_bSoundEngineInitialized))
  3242. {
  3243. return true;
  3244. }
  3245. if (UNLIKELY(bPermanentInitializationFailure))
  3246. {
  3247. return false;
  3248. }
  3249. SCOPED_AKAUDIO_EVENT_2(TEXT("FAkAudioDevice::EnsureInitialized"));
  3250. UE_CLOG(bLogWwiseVersionOnce, LogAkAudio, Log,
  3251. TEXT("Wwise(R) SDK Version %d.%d.%d Build %d [%s]. Copyright (c) 2006-%d Audiokinetic Inc."),
  3252. AK_WWISESDK_VERSION_MAJOR,
  3253. AK_WWISESDK_VERSION_MINOR,
  3254. AK_WWISESDK_VERSION_SUBMINOR,
  3255. AK_WWISESDK_VERSION_BUILD,
  3256. TEXT(WWISE_CONFIGURATION_DIR),
  3257. AK_WWISESDK_VERSION_MAJOR);
  3258. bLogWwiseVersionOnce = false;
  3259. auto* ResourceLoader = FWwiseResourceLoader::Get();
  3260. if (UNLIKELY(!ResourceLoader))
  3261. {
  3262. UE_LOG(LogAkAudio, Error, TEXT("Wwise Initialization Error: No ResourceLoader module"));
  3263. bPermanentInitializationFailure = true;
  3264. return false;
  3265. }
  3266. // We don't want sound in those cases.
  3267. if (AK_USE_NULL_SOUNDENGINE)
  3268. {
  3269. UE_LOG(LogAkAudio, Display, TEXT("Wwise SoundEngine is disabled: Using the null SoundEngine."));
  3270. UE_LOG(LogWwiseHints, Log, TEXT("Usage of the null SoundEngine is determined during UBT. Check UBT logs for more information."));
  3271. bPermanentInitializationFailure = true;
  3272. ResourceLoader->Disable();
  3273. return false;
  3274. }
  3275. if (FParse::Param(FCommandLine::Get(), TEXT("nosound")))
  3276. {
  3277. UE_LOG(LogAkAudio, Display, TEXT("Wwise SoundEngine is disabled: \"nosound\" command line parameter."));
  3278. bPermanentInitializationFailure = true;
  3279. ResourceLoader->Disable();
  3280. return false;
  3281. }
  3282. if (FApp::IsBenchmarking())
  3283. {
  3284. UE_LOG(LogAkAudio, Display, TEXT("Wwise SoundEngine is disabled: App is benchmarking."));
  3285. bPermanentInitializationFailure = true;
  3286. ResourceLoader->Disable();
  3287. return false;
  3288. }
  3289. if (IsRunningDedicatedServer())
  3290. {
  3291. UE_LOG(LogAkAudio, Display, TEXT("Wwise SoundEngine is disabled: Running a dedicated server."));
  3292. bPermanentInitializationFailure = true;
  3293. ResourceLoader->Disable();
  3294. return false;
  3295. }
  3296. if (IsRunningCommandlet())
  3297. {
  3298. UE_LOG(LogAkAudio, Display, TEXT("Wwise SoundEngine is disabled: Running a commandlet."));
  3299. bPermanentInitializationFailure = true;
  3300. ResourceLoader->Disable();
  3301. return false;
  3302. }
  3303. const UAkSettings* AkSettings = GetDefault<UAkSettings>();
  3304. if (UNLIKELY(!AkSettings))
  3305. {
  3306. UE_LOG(LogAkAudio, Error, TEXT("Wwise Initialization Error: No default settings."));
  3307. bPermanentInitializationFailure = true;
  3308. ResourceLoader->Disable();
  3309. return false;
  3310. }
  3311. if (!AkSettings->bWwiseSoundEngineEnabled)
  3312. {
  3313. UE_LOG(LogAkAudio, Display, TEXT("Wwise SoundEngine is disabled: Audio Routing is set to Enable Unreal Audio only."));
  3314. bPermanentInitializationFailure = true;
  3315. ResourceLoader->Disable();
  3316. return false;
  3317. }
  3318. auto* FileHandlerModule = IWwiseFileHandlerModule::GetModule();
  3319. if (UNLIKELY(!FileHandlerModule))
  3320. {
  3321. UE_LOG(LogAkAudio, Error, TEXT("Wwise Initialization Error: No file handling module"));
  3322. bPermanentInitializationFailure = true;
  3323. ResourceLoader->Disable();
  3324. return false;
  3325. }
  3326. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3327. if (UNLIKELY(!SoundEngine))
  3328. {
  3329. UE_LOG(LogAkAudio, Error, TEXT("Wwise Initialization Error: No Sound Engine"));
  3330. bPermanentInitializationFailure = true;
  3331. ResourceLoader->Disable();
  3332. return false;
  3333. }
  3334. IOHook = FileHandlerModule->InstantiateIOHook();
  3335. if (UNLIKELY(!IOHook))
  3336. {
  3337. UE_LOG(LogAkAudio, Error, TEXT("Wwise Initialization Error: No IO Hook"));
  3338. bPermanentInitializationFailure = true;
  3339. ResourceLoader->Disable();
  3340. return false;
  3341. }
  3342. // From this point on, if we get an error, we can try initializing later
  3343. if (UNLIKELY(!FAkSoundEngineInitialization::Initialize(IOHook)))
  3344. {
  3345. UE_LOG(LogAkAudio, Display, TEXT("Wwise Initialization Error."));
  3346. FAkSoundEngineInitialization::Finalize(IOHook);
  3347. delete IOHook;
  3348. IOHook = nullptr;
  3349. ResourceLoader->Disable();
  3350. return false;
  3351. }
  3352. UE_LOG(LogAkAudio, Log, TEXT("Wwise SoundEngine successfully initialized."));
  3353. SetLocalOutput();
  3354. // Init dummy game object
  3355. SoundEngine->RegisterGameObj(DUMMY_GAMEOBJ, "Unreal Global");
  3356. #if WITH_EDITOR
  3357. if (!IsRunningGame())
  3358. {
  3359. AkGameObjectID tempID = DUMMY_GAMEOBJ;
  3360. SoundEngine->SetListeners(DUMMY_GAMEOBJ, &tempID, 1);
  3361. }
  3362. #endif
  3363. m_bSoundEngineInitialized = true;
  3364. CallbackInfoPool = new AkCallbackInfoPool;
  3365. // Go get the max number of Aux busses
  3366. MaxAuxBus = AkSettings->MaxSimultaneousReverbVolumes;
  3367. //TUniquePtr
  3368. CallbackManager = new FAkComponentCallbackManager();
  3369. SetCurrentAudioCulture(GetDefaultLanguage());
  3370. UE_LOG(LogAkAudio, Log, TEXT("Initialization complete."));
  3371. return CallbackManager != nullptr;
  3372. }
  3373. void FAkAudioDevice::SetLocalOutput()
  3374. {
  3375. auto* Monitor = IWwiseMonitorAPI::Get();
  3376. if (UNLIKELY(!Monitor))
  3377. {
  3378. return;
  3379. }
  3380. Monitor->ResetTranslator();
  3381. #if WITH_EDITORONLY_DATA && !defined(AK_OPTIMIZED)
  3382. const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
  3383. if (AkSettingsPerUser->WaapiTranslatorTimeout > 0)
  3384. {
  3385. #if AK_SUPPORT_WAAPI
  3386. Monitor->SetupDefaultWAAPIErrorTranslator(AkSettingsPerUser->WaapiIPAddress, AkSettingsPerUser->WaapiPort, AkSettingsPerUser->WaapiTranslatorTimeout);
  3387. #endif //AK_SUPPORT_WAAPI
  3388. }
  3389. if (!m_UnrealErrorTranslator)
  3390. {
  3391. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3392. if (UNLIKELY(!SoundEngine))
  3393. {
  3394. return;
  3395. }
  3396. m_UnrealErrorTranslator = SoundEngine->NewErrorMessageTranslator(&GetInfoErrorMessageTranslatorFunction);
  3397. }
  3398. if (m_UnrealErrorTranslator)
  3399. {
  3400. Monitor->AddTranslator(m_UnrealErrorTranslator);
  3401. }
  3402. #endif
  3403. }
  3404. void FAkAudioDevice::AddDefaultListener(UAkComponent* in_pListener)
  3405. {
  3406. bool bAlreadyInSet;
  3407. m_defaultListeners.Add(in_pListener, &bAlreadyInSet);
  3408. if (!bAlreadyInSet)
  3409. {
  3410. for (TObjectIterator<UAkComponent> Emitter; Emitter; ++Emitter)
  3411. {
  3412. Emitter->OnDefaultListenerAdded(in_pListener);
  3413. }
  3414. in_pListener->IsListener = true;
  3415. in_pListener->IsDefaultListener = true;
  3416. UpdateDefaultActiveListeners();
  3417. if (m_SpatialAudioListener == nullptr)
  3418. SetSpatialAudioListener(in_pListener);
  3419. }
  3420. }
  3421. void FAkAudioDevice::RemoveDefaultListener(UAkComponent* in_pListener)
  3422. {
  3423. for (TObjectIterator<UAkComponent> Emitter; Emitter; ++Emitter)
  3424. {
  3425. Emitter->OnListenerUnregistered(in_pListener);
  3426. }
  3427. m_defaultListeners.Remove(in_pListener);
  3428. in_pListener->IsListener = false;
  3429. in_pListener->IsDefaultListener = false;
  3430. UpdateDefaultActiveListeners();
  3431. // We are setting Aux Sends with the SpatialAudio API, and that requires a Spatial Audio listener.
  3432. // When running dedicated server, Unreal creates a camera manager (default listener 1 gets set as spatial audio listener), then another one (default listener 2), and then destroys the first. This leaves us with a default listener, but no spatial audio listener. This fix targets that issue.
  3433. if (m_SpatialAudioListener == in_pListener )
  3434. {
  3435. // Unregister the Spatial Audio Listener if its game object is unregistered
  3436. auto* SpatialAudio = IWwiseSpatialAudioAPI::Get();
  3437. if (LIKELY(SpatialAudio))
  3438. {
  3439. SpatialAudio->UnregisterListener(m_SpatialAudioListener->GetAkGameObjectID());
  3440. }
  3441. m_SpatialAudioListener = nullptr;
  3442. if (m_defaultListeners.Num() > 0)
  3443. {
  3444. for (auto listener : m_defaultListeners)
  3445. {
  3446. if (SetSpatialAudioListener(m_defaultListeners.Array()[0]))
  3447. {
  3448. break;
  3449. }
  3450. }
  3451. }
  3452. }
  3453. }
  3454. void FAkAudioDevice::OnActorSpawned(AActor* SpawnedActor)
  3455. {
  3456. APlayerCameraManager* AsPlayerCameraManager = Cast<APlayerCameraManager>(SpawnedActor);
  3457. if (AsPlayerCameraManager && AsPlayerCameraManager->GetWorld()->AllowAudioPlayback())
  3458. {
  3459. APlayerController* CameraOwner = Cast<APlayerController>(AsPlayerCameraManager->GetOwner());
  3460. if (CameraOwner && CameraOwner->IsLocalPlayerController())
  3461. {
  3462. UAkComponent* pAkComponent = NewObject<UAkComponent>(SpawnedActor);
  3463. if (pAkComponent != nullptr)
  3464. {
  3465. pAkComponent->RegisterComponentWithWorld(SpawnedActor->GetWorld());
  3466. pAkComponent->AttachToComponent(SpawnedActor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform, FName());
  3467. AddDefaultListener(pAkComponent);
  3468. }
  3469. }
  3470. }
  3471. }
  3472. FString FAkAudioDevice::GetBasePath()
  3473. {
  3474. return WwiseUnrealHelper::GetSoundBankDirectory();
  3475. }
  3476. /**
  3477. * Allocates memory from permanent pool. This memory will NEVER be freed.
  3478. *
  3479. * @param Size Size of allocation.
  3480. *
  3481. * @return pointer to a chunk of memory with size Size
  3482. */
  3483. void* FAkAudioDevice::AllocatePermanentMemory( int32 Size, bool& AllocatedInPool )
  3484. {
  3485. return 0;
  3486. }
  3487. AKRESULT FAkAudioDevice::GetGameObjectID( AActor * in_pActor, AkGameObjectID& io_GameObject )
  3488. {
  3489. if ( IsValid(in_pActor) )
  3490. {
  3491. UAkComponent * pComponent = GetAkComponent( in_pActor->GetRootComponent(), FName(), NULL, EAttachLocation::KeepRelativeOffset );
  3492. if ( pComponent )
  3493. {
  3494. io_GameObject = pComponent->GetAkGameObjectID();
  3495. return AK_Success;
  3496. }
  3497. else
  3498. return AK_Fail;
  3499. }
  3500. // we do not modify io_GameObject, letting it to the specified default value.
  3501. return AK_Success;
  3502. }
  3503. AKRESULT FAkAudioDevice::GetGameObjectID( AActor * in_pActor, AkGameObjectID& io_GameObject, bool in_bStopWhenOwnerDestroyed )
  3504. {
  3505. if ( IsValid(in_pActor) )
  3506. {
  3507. UAkComponent * pComponent = GetAkComponent( in_pActor->GetRootComponent(), FName(), NULL, EAttachLocation::KeepRelativeOffset );
  3508. if ( pComponent )
  3509. {
  3510. pComponent->StopWhenOwnerDestroyed = in_bStopWhenOwnerDestroyed;
  3511. io_GameObject = pComponent->GetAkGameObjectID();
  3512. return AK_Success;
  3513. }
  3514. else
  3515. return AK_Fail;
  3516. }
  3517. // we do not modify io_GameObject, letting it to the specified default value.
  3518. return AK_Success;
  3519. }
  3520. void FAkAudioDevice::Suspend(bool in_bRenderAnyway /* = false */)
  3521. {
  3522. if (!m_isSuspended)
  3523. {
  3524. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3525. if (UNLIKELY(!SoundEngine)) return;
  3526. SoundEngine->Suspend(in_bRenderAnyway);
  3527. m_isSuspended = true;
  3528. }
  3529. }
  3530. void FAkAudioDevice::WakeupFromSuspend()
  3531. {
  3532. if (m_isSuspended)
  3533. {
  3534. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3535. if (UNLIKELY(!SoundEngine)) return;
  3536. SoundEngine->WakeupFromSuspend();
  3537. m_isSuspended = false;
  3538. }
  3539. }
  3540. void FAkAudioDevice::StartOutputCapture(const FString& Filename)
  3541. {
  3542. if ( m_bSoundEngineInitialized )
  3543. {
  3544. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3545. if (UNLIKELY(!SoundEngine)) return;
  3546. SoundEngine->StartOutputCapture(TCHAR_TO_AK(*Filename));
  3547. }
  3548. }
  3549. void FAkAudioDevice::StopOutputCapture()
  3550. {
  3551. if ( m_bSoundEngineInitialized )
  3552. {
  3553. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3554. if (UNLIKELY(!SoundEngine)) return;
  3555. SoundEngine->StopOutputCapture();
  3556. }
  3557. }
  3558. void FAkAudioDevice::StartProfilerCapture(const FString& Filename)
  3559. {
  3560. if ( m_bSoundEngineInitialized )
  3561. {
  3562. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3563. if (UNLIKELY(!SoundEngine)) return;
  3564. SoundEngine->StartProfilerCapture(TCHAR_TO_AK(*Filename));
  3565. }
  3566. }
  3567. void FAkAudioDevice::AddOutputCaptureMarker(const FString& MarkerText)
  3568. {
  3569. if ( m_bSoundEngineInitialized )
  3570. {
  3571. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3572. if (UNLIKELY(!SoundEngine)) return;
  3573. SoundEngine->AddOutputCaptureMarker(TCHAR_TO_ANSI(*MarkerText));
  3574. }
  3575. }
  3576. void FAkAudioDevice::StopProfilerCapture()
  3577. {
  3578. if ( m_bSoundEngineInitialized )
  3579. {
  3580. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3581. if (UNLIKELY(!SoundEngine)) return;
  3582. SoundEngine->StopProfilerCapture();
  3583. }
  3584. }
  3585. AKRESULT FAkAudioDevice::RegisterPluginDLL(const FString& in_DllName, const FString& in_DllPath)
  3586. {
  3587. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3588. if (UNLIKELY(!SoundEngine)) return AK_NotInitialized;
  3589. AkOSChar* szPath = nullptr;
  3590. if (!in_DllPath.IsEmpty())
  3591. {
  3592. auto Length = in_DllPath.Len() + 1;
  3593. szPath = new AkOSChar[Length];
  3594. AKPLATFORM::SafeStrCpy(szPath, TCHAR_TO_AK(*in_DllPath), Length);
  3595. }
  3596. AKRESULT eResult = SoundEngine->RegisterPluginDLL(TCHAR_TO_AK(*in_DllName), szPath);
  3597. delete[] szPath;
  3598. return eResult;
  3599. }
  3600. // end
  3601. FAkAudioDevice::SetCurrentAudioCultureAsyncTask::SetCurrentAudioCultureAsyncTask(FWwiseLanguageCookedData NewLanguage, FSetCurrentAudioCultureAction* LatentAction)
  3602. : Language(NewLanguage)
  3603. , SetAudioCultureLatentAction(LatentAction)
  3604. {
  3605. CompletionActionType = CompletionType::LatentAction;
  3606. LatentActionValidityToken = MakeShared<FPendingLatentActionValidityToken, ESPMode::ThreadSafe>();
  3607. SetAudioCultureLatentAction->ValidityToken = LatentActionValidityToken;
  3608. }
  3609. FAkAudioDevice::SetCurrentAudioCultureAsyncTask::SetCurrentAudioCultureAsyncTask(FWwiseLanguageCookedData NewLanguage, const FOnSetCurrentAudioCultureCompleted& CompletedCallback)
  3610. : Language(NewLanguage)
  3611. , SetAudioCultureCompletedCallback(CompletedCallback)
  3612. {
  3613. CompletionActionType = CompletionType::Callback;
  3614. }
  3615. bool FAkAudioDevice::SetCurrentAudioCultureAsyncTask::Start()
  3616. {
  3617. UE_LOG(LogAkAudio, Verbose, TEXT("Switching Wwise language to '%s'"), *Language.GetLanguageName().ToString());
  3618. auto* StreamMgr = IWwiseStreamMgrAPI::Get();
  3619. if (UNLIKELY(!StreamMgr))
  3620. {
  3621. return false;
  3622. }
  3623. StreamMgr->SetCurrentLanguage(TCHAR_TO_AK(*Language.GetLanguageName().ToString()));
  3624. AsyncTask(ENamedThreads::AnyNormalThreadNormalTask, [this]()
  3625. {
  3626. auto* ResourceLoader = FWwiseResourceLoader::Get();
  3627. if (UNLIKELY(!ResourceLoader))
  3628. {
  3629. UE_LOG(LogAkAudio, Error, TEXT("SetCurrentAudioCultureAsync: Could not get resource loader, cannot change language."));
  3630. Succeeded = false;
  3631. IsDone = true;
  3632. return;
  3633. }
  3634. ResourceLoader->SetLanguage(Language, EWwiseReloadLanguage::Immediate);
  3635. IsDone = true;
  3636. Succeeded = true;
  3637. });
  3638. return true;
  3639. }
  3640. void FAkAudioDevice::SetCurrentAudioCultureAsyncTask::Update()
  3641. {
  3642. if (IsDone)
  3643. {
  3644. switch (CompletionActionType)
  3645. {
  3646. case CompletionType::Callback:
  3647. SetAudioCultureCompletedCallback.ExecuteIfBound(Succeeded);
  3648. break;
  3649. case CompletionType::LatentAction:
  3650. if (LatentActionValidityToken->bValid && SetAudioCultureLatentAction)
  3651. {
  3652. SetAudioCultureLatentAction->ActionDone = true;
  3653. }
  3654. break;
  3655. }
  3656. }
  3657. }
  3658. void FAkAudioDevice::AddPlayingID(uint32 EventID, uint32 PlayingID, EAkAudioContext AudioContext)
  3659. {
  3660. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  3661. auto& PlayingIDArray = EventToPlayingIDMap.FindOrAdd(EventID);
  3662. PlayingIDArray.Add(PlayingID);
  3663. PlayingIDToAudioContextMap.Add(PlayingID, AudioContext);
  3664. }
  3665. bool FAkAudioDevice::IsPlayingIDActive(uint32 EventID, uint32 PlayingID)
  3666. {
  3667. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  3668. auto* PlayingIDArray = EventToPlayingIDMap.Find(EventID);
  3669. if (PlayingIDArray && PlayingIDArray->Contains(PlayingID))
  3670. {
  3671. return true;
  3672. }
  3673. return false;
  3674. }
  3675. bool FAkAudioDevice::IsEventIDActive(uint32 EventID)
  3676. {
  3677. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  3678. return EventToPlayingIDMap.Contains(EventID);
  3679. }
  3680. void FAkAudioDevice::RemovePlayingID(uint32 EventID, uint32 PlayingID)
  3681. {
  3682. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  3683. auto* PlayingIDArray = EventToPlayingIDMap.Find(EventID);
  3684. if (PlayingIDArray)
  3685. {
  3686. PlayingIDArray->Remove(PlayingID);
  3687. if (PlayingIDArray->Num() == 0)
  3688. {
  3689. EventToPlayingIDMap.Remove(EventID);
  3690. PlayingIDToAudioContextMap.Remove(PlayingID);
  3691. }
  3692. }
  3693. }
  3694. void FAkAudioDevice::StopEventID(uint32 EventID)
  3695. {
  3696. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  3697. if (UNLIKELY(!SoundEngine)) return;
  3698. FScopeLock Lock(&EventToPlayingIDMapCriticalSection);
  3699. auto* PlayingIDs = EventToPlayingIDMap.Find(EventID);
  3700. if (PlayingIDs)
  3701. {
  3702. for (auto pID : *PlayingIDs)
  3703. {
  3704. StopPlayingID(pID);
  3705. }
  3706. SoundEngine->RenderAudio();
  3707. }
  3708. }
  3709. FOnSwitchValueLoaded& FAkAudioDevice::GetOnSwitchValueLoaded(uint32 SwitchID)
  3710. {
  3711. return OnSwitchValueLoadedMap.FindOrAdd(SwitchID);
  3712. }
  3713. void FAkAudioDevice::BroadcastOnSwitchValueLoaded(UAkGroupValue* GroupValue)
  3714. {
  3715. FOnSwitchValueLoaded* EventToBroadcast = OnSwitchValueLoadedMap.Find(GroupValue->GetShortID());
  3716. if (EventToBroadcast)
  3717. {
  3718. EventToBroadcast->Broadcast(GroupValue);
  3719. }
  3720. }
  3721. void FAkAudioDevice::AddPortalConnectionToOutdoors(const UWorld* in_world, UAkPortalComponent* in_pPortal)
  3722. {
  3723. if (in_world == nullptr)
  3724. {
  3725. return;
  3726. }
  3727. OutdoorsConnectedPortals.FindOrAdd(in_world).Add(in_pPortal->GetPortalID(), in_pPortal);
  3728. }
  3729. void FAkAudioDevice::RemovePortalConnectionToOutdoors(const UWorld* in_world, AkPortalID in_portalID)
  3730. {
  3731. if (in_world == nullptr)
  3732. {
  3733. return;
  3734. }
  3735. auto pPortals = OutdoorsConnectedPortals.Find(in_world);
  3736. if (pPortals == nullptr)
  3737. {
  3738. return;
  3739. }
  3740. pPortals->Remove(in_portalID);
  3741. }
  3742. void FAkAudioDevice::GetObsOccServicePortalMap(const UAkRoomComponent* InRoom, const UWorld* InWorld, AkObstructionAndOcclusionService::PortalMap& OutPortalMap) const
  3743. {
  3744. PortalComponentMap ConnectedPortals;
  3745. if (InRoom != nullptr)
  3746. {
  3747. ConnectedPortals = InRoom->GetConnectedPortals();
  3748. }
  3749. else
  3750. {
  3751. auto Portals = OutdoorsConnectedPortals.Find(InWorld);
  3752. if (Portals != nullptr)
  3753. {
  3754. ConnectedPortals = *Portals;
  3755. }
  3756. }
  3757. for (auto& Portal : ConnectedPortals)
  3758. {
  3759. AkObstructionAndOcclusionService::FPortalInfo PortalInfo(Portal.Value->Bounds.GetBox().GetCenter(), Portal.Value->ObstructionRefreshInterval != 0.f);
  3760. OutPortalMap.Add(Portal.Key, PortalInfo);
  3761. }
  3762. }