AkAudioDevice.cpp 149 KB

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