1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231 |
- /*******************************************************************************
- The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
- Technology released in source code form as part of the game integration package.
- The content of this file may not be used without valid licenses to the
- AUDIOKINETIC Wwise Technology.
- Note that the use of the game engine is subject to the Unreal(R) Engine End User
- License Agreement at https://www.unrealengine.com/en-US/eula/unreal
-
- License Usage
-
- Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
- this file in accordance with the end user license agreement provided with the
- software or, alternatively, in accordance with the terms contained
- in a written agreement between you and Audiokinetic Inc.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- /*=============================================================================
- AkWaapiClient.cpp: Audiokinetic WAAPI interface object.
- Unreal is RHS with Y and Z swapped (or technically LHS with flipped axis)
- =============================================================================*/
- /*------------------------------------------------------------------------------------
- Audio includes.
- ------------------------------------------------------------------------------------*/
- #include "AkWaapiClient.h"
- #include "AkAudioDevice.h"
- #include "AkSettings.h"
- #include "AkSettingsPerUser.h"
- #include "WwiseUnrealDefines.h"
- #include "Serialization/JsonSerializer.h"
- #include "Async/Async.h"
- #include "Misc/ScopeLock.h"
- #include "Misc/CoreDelegates.h"
- #include "Wwise/API/WAAPI.h"
- #if AK_SUPPORT_WAAPI
- #include "Misc/App.h"
- #include "Misc/Paths.h"
- #if PLATFORM_WINDOWS
- // Problem with the Windows API as a whole: it uses noexcept straight up, whether exceptions are used or not, generating a warning that Unreal then converts to an error.
- #if _MSC_VER >= 1910
- #pragma warning (disable: 4577)
- #endif // _MSC_VER >= 1910
- #endif // #if PLATFORM_WINDOWS
- typedef AK::WwiseAuthoringAPI::JsonProvider JsonProvider;
- #endif
- /*------------------------------------------------------------------------------------
- Statics and Globals
- ------------------------------------------------------------------------------------*/
- FAkWaapiClient* g_AkWaapiClient = nullptr;
- /*------------------------------------------------------------------------------------
- FAkWaapiClientConnectionHandler
- ------------------------------------------------------------------------------------*/
- FAkWaapiClientConnectionHandler::FAkWaapiClientConnectionHandler(FAkWaapiClient& in_Client) : m_Client(in_Client)
- {
- WaitEvent = FPlatformProcess::GetSynchEventFromPool(true);
- }
- FAkWaapiClientConnectionHandler::~FAkWaapiClientConnectionHandler()
- {
- FPlatformProcess::ReturnSynchEventToPool(WaitEvent);
- WaitEvent = nullptr;
- }
- void FAkWaapiClientConnectionHandler::RegisterAutoConnectChangedCallback()
- {
- #if WITH_EDITOR
- FScopeLock Lock(&AkSettingsSection);
- if (auto AkSettingsPerUser = GetDefault<UAkSettingsPerUser>())
- {
- AutoConnectChangedHandle = AkSettingsPerUser->OnAutoConnectToWaapiChanged.AddLambda([this, AkSettingsPerUser]()
- {
- ResetReconnectionDelay();
- if (AkSettingsPerUser->bAutoConnectToWAAPI)
- WaitEvent->Trigger();
- else
- {
- m_Client.BroadcastConnectionLost();
- }
- });
- }
- #endif
- }
- void FAkWaapiClientConnectionHandler::Wake()
- {
- WaitEvent->Trigger();
- }
- /* FRunnable interface */
- bool FAkWaapiClientConnectionHandler::Init()
- {
- return true;
- }
- uint32 FAkWaapiClientConnectionHandler::Run()
- {
- #if AK_SUPPORT_WAAPI
- checkf(!IsInGameThread(), TEXT("FAkWaapiClientConnectionHandler::Run: Cannot be run in Game Thread."));
- while (!ThreadShouldExit)
- {
- if (!m_Client.IsProjectLoaded())
- {
- /** Check if we should attempt to reconnect according to the Wwise Plugin Settings. */
- bool bReconnect = !m_Client.IsDisconnecting() && !m_Client.AppIsExiting();
- {
- FScopeLock Lock(&AkSettingsSection);
- if (auto AkSettingsPerUser = GetDefault<UAkSettingsPerUser>())
- {
- bReconnect = AkSettingsPerUser->bAutoConnectToWAAPI;
- }
- }
- /** If we previously had a connection (and we're not exiting), broadcast connection lost.*/
- if (hadConnection && !m_Client.AppIsExiting())
- {
- if (bReconnect)
- UE_LOG(LogAkAudio, Warning, TEXT("Lost connection to WAAPI client. Attempting reconnection ..."));
- hadConnection = false;
- AsyncTask(ENamedThreads::GameThread, [this]()
- {
- m_Client.BroadcastConnectionLost();
- });
- }
- /** If we should reconnect, attempt a reconnection and, if successful, call the client's connection established function on the game thread.
- * Otherwise, print a failed connection log.
- */
- if (bReconnect)
- {
- if (AttemptReconnect())
- {
- hadConnection = true;
- m_Client.SetConnectionClosing(false);
- ResetReconnectionDelay();
- AsyncTask(ENamedThreads::GameThread, [this]()
- {
- m_Client.ConnectionEstablished();
- });
- }
- else
- {
- if (LogOutputCount.GetValue() < 7)
- {
- UE_LOG(LogAkAudio, Warning, TEXT("Failed to connect to WAAPI client on local host. Trying again in %i seconds."), ReconnectDelay.GetValue());
- LogOutputCount.Increment();
- }
- }
- /** Delay the next reconnection attempt according to the ReconnectDelay value. */
- const int iCurrentDelay = ReconnectDelay.GetValue();
- if (iCurrentDelay < m_iMaxReconnectDelay)
- ReconnectDelay.Set(iCurrentDelay * 2);
- WaitEvent->Wait(iCurrentDelay * 1000);
- WaitEvent->Reset();
- }
- else
- {
- /** We shouldn't attempt reconnection, so wait until the auto-reconnect option is changed. */
- WaitEvent->Wait();
- WaitEvent->Reset();
- }
- }
- else /** We're already connected. Check connection status. */
- {
- TSharedRef<FJsonObject> args = MakeShareable(new FJsonObject());
- TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
- TSharedPtr<FJsonObject> result = MakeShareable(new FJsonObject());
- m_Client.Call(ak::wwise::core::getInfo, args, options, result, 500, true);
- WaitEvent->Wait(ConnectionMonitorDelay.GetValue() * 1000);
- WaitEvent->Reset();
- }
- }
- #endif
- return 0;
- }
- void FAkWaapiClientConnectionHandler::ResetReconnectionDelay()
- {
- bool bReconnect = true;
- {
- FScopeLock Lock(&AkSettingsSection);
- if (auto AkSettingsPerUser = GetDefault<UAkSettingsPerUser>())
- {
- bReconnect = AkSettingsPerUser->bAutoConnectToWAAPI;
- }
- }
- if (bReconnect && !m_Client.AppIsExiting() && !m_Client.IsDisconnecting())
- {
- ReconnectDelay.Set(2);
- LogOutputCount.Set(0);
- }
- }
- void FAkWaapiClientConnectionHandler::Stop()
- {
- ThreadShouldExit = true;
- }
- void FAkWaapiClientConnectionHandler::Exit()
- {
- ThreadShouldExit = true;
- }
- bool FAkWaapiClientConnectionHandler::AttemptReconnect()
- {
- #if AK_SUPPORT_WAAPI
- if (m_Client.AttemptConnection())
- {
- UE_LOG(LogAkAudio, Log, TEXT("Successfully connected to Wwise Authoring on localhost."));
- return true;
- }
- #endif
- return false;
- }
- /*------------------------------------------------------------------------------------
- Helpers
- ------------------------------------------------------------------------------------*/
- struct FAkWaapiClientImpl
- {
- void Init(FAkWaapiClient& in_Client)
- {
- #if AK_SUPPORT_WAAPI
- if (FApp::IsUnattended())
- {
- UE_LOG(LogAkAudio, Display, TEXT("WAAPI client is disabled. Unattended mode."));
- return;
- }
- auto* WAAPI = IWAAPI::Get();
- if (UNLIKELY(!WAAPI))
- {
- UE_LOG(LogAkAudio, Display, TEXT("WAAPI client is disabled. WAAPI is unavailable."));
- return;
- }
- m_Client = WAAPI->NewClient();
- if (UNLIKELY(!m_Client))
- {
- UE_LOG(LogAkAudio, Display, TEXT("WAAPI client is disabled. Client cannot be enabled."));
- return;
- }
- m_pConnectionHandler = MakeShareable(new FAkWaapiClientConnectionHandler(in_Client));
- FString ThreadName(FString::Printf(TEXT("WAAPIClientConnectionThread%i"), ThreadCounter.Increment()));
- m_pReconnectionThread = MakeShareable(FRunnableThread::Create(m_pConnectionHandler.Get(),
- *ThreadName, 0,
- EThreadPriority::TPri_BelowNormal));
- m_pConnectionHandler->RegisterAutoConnectChangedCallback();
- #else
- UE_LOG(LogAkAudio, Verbose, TEXT("WAAPI client is disabled. Configuration doesn't support WAAPI."));
- #endif
- }
- ~FAkWaapiClientImpl()
- {
- #if AK_SUPPORT_WAAPI
- if (m_pConnectionHandler.IsValid())
- {
- m_pConnectionHandler->Exit();
- m_pConnectionHandler->Wake();
- }
- if (m_pReconnectionThread.IsValid())
- {
- if (!m_pReconnectionThread->Kill(true))
- {
- UE_LOG(LogAkAudio, Error, TEXT("WAAPI Connection Thread Failed to Exit!"));
- }
- }
- delete m_Client; m_Client = nullptr;
- #endif
- }
- #if AK_SUPPORT_WAAPI
- /** Map containing id keys and WampEventCallback values. */
- TMap<uint64_t, WampEventCallback> m_wampEventCallbackMap;
- IWAAPI::Client* m_Client = nullptr;
- /** A non-0 value indicates that UE is exiting. */
- FThreadSafeCounter AppExitingCounter = 0;
- FThreadSafeCounter ThreadCounter;
- /** Thread on which the WAAPI connection is monitored. */
- TSharedPtr<FRunnableThread> m_pReconnectionThread;
- /** The connection to WAAPI is monitored by this connection handler.
- * It tries to reconnect when connection is lost, and continuously polls WAAPI for the connection status when WAAPI is connected.
- * This behaviour can be disabled in AkSettings using the AutoConnectToWaapi boolean option.
- */
- TSharedPtr<FAkWaapiClientConnectionHandler> m_pConnectionHandler;
- FCriticalSection ClientSection;
- /** Flag indicating whether the correct project has been loaded (it's "correct" if it matches the Project Path in AkSettings.) */
- FThreadSafeBool bProjectLoaded = false;
- /** Flag indicating if the connection is being killed and shouldn't be restarted. */
- FThreadSafeBool bIsConnectionClosing = false;
- #endif
- };
- bool FAkWaapiClient::JsonObjectToString(const TSharedRef<FJsonObject>& in_jsonObject, FString& ou_jsonObjectString)
- {
- TSharedRef<TJsonWriter<>> JsonWriterArgs = TJsonWriterFactory<>::Create(&ou_jsonObjectString);
- auto result = FJsonSerializer::Serialize(in_jsonObject, JsonWriterArgs);
- if (!result)
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to get a string representation of the Json Object."));
- }
- JsonWriterArgs->Close();
- return result;
- }
- #if AK_SUPPORT_WAAPI
- void WampEventCallbacks(const uint64_t& in_subscriptionId, const JsonProvider& in_rJson)
- {
- if (g_AkWaapiClient == nullptr)
- return;
- auto wampEventCallbacks = g_AkWaapiClient->GetWampEventCallback(in_subscriptionId);
- if (!wampEventCallbacks)
- return;
- auto* WAAPI = IWAAPI::Get();
- if (UNLIKELY(!WAAPI))
- {
- return;
- }
- TSharedPtr<FJsonObject> ueJsonObject;
- TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(UTF8_TO_TCHAR(WAAPI->GetJsonString(in_rJson).c_str()));
- if (!FJsonSerializer::Deserialize(Reader, ueJsonObject) || !ueJsonObject.IsValid())
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to deserialize a JSON object from the string : %s"), UTF8_TO_TCHAR(WAAPI->GetJsonString(in_rJson).c_str()));
- return;
- }
- wampEventCallbacks->Execute(in_subscriptionId, ueJsonObject);
- }
- #endif
- /*------------------------------------------------------------------------------------
- Implementation.
- ------------------------------------------------------------------------------------*/
- FAkWaapiClient::~FAkWaapiClient()
- {
- delete m_Impl;
- }
- void FAkWaapiClient::Initialize()
- {
- #if AK_SUPPORT_WAAPI
- if (!g_AkWaapiClient)
- {
- g_AkWaapiClient = new FAkWaapiClient();
- if(g_AkWaapiClient)
- {
- g_AkWaapiClient->m_Impl->Init(*g_AkWaapiClient);
- }
- FCoreDelegates::OnPreExit.AddLambda([]
- {
- if (g_AkWaapiClient != nullptr)
- {
- g_AkWaapiClient->m_Impl->AppExitingCounter.Increment();
- TArray<uint64_t> aSubscriptionIDs;
- g_AkWaapiClient->m_Impl->m_wampEventCallbackMap.GetKeys(aSubscriptionIDs);
- TSharedPtr<FJsonObject> jsonResult = MakeShareable(new FJsonObject());
- for (auto iSubscriptionID : aSubscriptionIDs)
- {
- g_AkWaapiClient->Unsubscribe(iSubscriptionID, jsonResult);
- }
- }
- DeleteInstance();
- });
- }
- #endif
- }
- /** Returns the singleton instance of FAkWaapiClient. Be sure to call FAkWaapiClient::Initialize() first (i.e. during Module startup). */
- FAkWaapiClient* FAkWaapiClient::Get()
- {
- return g_AkWaapiClient;
- }
- bool FAkWaapiClient::AppIsExiting()
- {
- #if AK_SUPPORT_WAAPI
- return m_Impl->AppExitingCounter.GetValue() != 0;
- #else
- return false;
- #endif
- }
- void FAkWaapiClient::SetConnectionClosing(bool isClosing)
- {
- #if AK_SUPPORT_WAAPI
- m_Impl->bIsConnectionClosing = isClosing;
- #endif
- }
- void FAkWaapiClient::DeleteInstance()
- {
- #if AK_SUPPORT_WAAPI
- if (g_AkWaapiClient == nullptr)
- return;
- g_AkWaapiClient->OnClientBeginDestroy.Broadcast();
- g_AkWaapiClient->m_Impl->bIsConnectionClosing = true;
- if (g_AkWaapiClient->m_Impl->m_Client)
- {
- g_AkWaapiClient->m_Impl->m_Client->Disconnect();
- }
- delete g_AkWaapiClient;
- g_AkWaapiClient = nullptr;
- #endif
- }
- bool FAkWaapiClient::IsDisconnecting()
- {
- #if AK_SUPPORT_WAAPI
- return m_Impl->bIsConnectionClosing;
- #else
- return false;
- #endif
- }
- WampEventCallback* FAkWaapiClient::GetWampEventCallback(const uint64_t& in_subscriptionId)
- {
- #if AK_SUPPORT_WAAPI
- return m_Impl->m_wampEventCallbackMap.Find(in_subscriptionId);
- #else
- return nullptr;
- #endif
- }
- bool FAkWaapiClient::IsProjectLoaded()
- {
- #if AK_SUPPORT_WAAPI
- if (g_AkWaapiClient == nullptr)
- return false;
- if (!g_AkWaapiClient->IsConnected())
- {
- return false;
- }
- return g_AkWaapiClient->m_Impl->bProjectLoaded;
- #else
- return false;
- #endif
- }
- /** This is called when the reconnection handler successfully connects to WAAPI.
- * We check if the correct project is loaded on a background thread. If it is, we broadcast OnProjectLoaded.
- * We also subscribe to ak::wwise::core::project::loaded in order to check the project whenever one is loaded.
- * If an incorrect project is loaded we broadcast OnConnectionLost.
- */
- void FAkWaapiClient::ConnectionEstablished()
- {
- #if AK_SUPPORT_WAAPI
- ensure(IsInGameThread());
- if (g_AkWaapiClient == nullptr)
- return;
- // Broadcast OnProjectLoaded. If we are here, it means connection was successful, and that the correct project is
- // loaded and available
- OnProjectLoaded.Broadcast();
- //We also subscribe to ak::wwise::core::project::loaded in order to check the project whenever one is loaded.
- auto projectLoadedCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> in_UEJsonObject)
- {
- AsyncTask(ENamedThreads::GameThread, [this, id, in_UEJsonObject]()
- {
- m_Impl->bProjectLoaded = CheckProjectLoaded();
- if (m_Impl->bProjectLoaded)
- {
- OnProjectLoaded.Broadcast();
- }
- else if (!AppIsExiting())//If an incorrect project is loaded we broadcast OnConnectionLost
- {
- BroadcastConnectionLost();
- }
- });
- });
- TSharedPtr<FJsonObject> projectLoadedSubscriptionResult = MakeShareable(new FJsonObject());
- TSharedRef<FJsonObject> projectLoadedOptions = MakeShareable(new FJsonObject());
- uint64_t projectLoadedSubscriptionID;
- g_AkWaapiClient->Subscribe(ak::wwise::core::project::loaded, projectLoadedOptions, projectLoadedCallback, projectLoadedSubscriptionID, projectLoadedSubscriptionResult);
- //And we need to subscribe to ak::wwise::core::project::postClosed such that we are able to re-connect to WAAPI (for example if Wwise is closed then opened again).
- auto projectClosedCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> in_UEJsonObject)
- {
- AsyncTask(ENamedThreads::GameThread, [this]()
- {
- BroadcastConnectionLost();
- });
- });
- TSharedPtr<FJsonObject> projectClosedSubscriptionResult = MakeShareable(new FJsonObject());
- TSharedRef<FJsonObject> projectClosedOptions = MakeShareable(new FJsonObject());
- uint64_t projectClosedSubscriptionID;
- g_AkWaapiClient->Subscribe(ak::wwise::core::project::postClosed, projectClosedOptions, projectClosedCallback, projectClosedSubscriptionID, projectClosedSubscriptionResult);
- #endif
- }
- /** Returns the path of the Wwise project as defined in AkSettings (WWise Plugin Settings). */
- bool FAkWaapiClient::GetProjectPath(TSharedPtr<FJsonObject>& inOutJsonResult, FString& ProjectPath)
- {
- #if AK_SUPPORT_WAAPI
- TArray<TSharedPtr<FJsonValue>> inFromItems;
- inFromItems.Add(MakeShareable(new FJsonValueString("Project")));
- const bool bSuccess = WAAPIGet(WAAPIGetFromOption::OF_TYPE, inFromItems, (AkInt64)WAAPIGetReturnOptionFlag::FILEPATH,
- inOutJsonResult, WAAPIGetTransformOption::NONE, TArray<TSharedPtr<FJsonValue>>(), true);
- if (bSuccess)
- {
- if (inOutJsonResult->HasField(FAkWaapiClient::WAAPIStrings::RETURN))
- {
- TArray<TSharedPtr<FJsonValue>> returnJson = inOutJsonResult->GetArrayField(FAkWaapiClient::WAAPIStrings::RETURN);
- if (returnJson.Num() > 0)
- ProjectPath = returnJson[0]->AsObject()->GetStringField(FAkWaapiClient::WAAPIStrings::FILEPATH);
- }
- }
- return bSuccess;
- #else
- return true;
- #endif
- }
- // WAAPI can become temporarily unavailable from time to time, this should be taken into account in the design.
- // Please note that you shouldn't use this kind of design unless you know your call is accurate. If you do this
- // and the error is caused by an argument problem, you might end up with an infinite retry loop.
- FString GetAndWaitForCurrentProject(float RetrySleepTimeSeconds)
- {
- FString ProjectPath;
- static int RetryCount = 5;
- while (g_AkWaapiClient->IsConnected())
- {
- TSharedPtr<FJsonObject> JsonResult = MakeShareable(new FJsonObject());
- if (g_AkWaapiClient->GetProjectPath(JsonResult, ProjectPath))
- break;
- if (RetrySleepTimeSeconds > 0.0f)
- {
- if (--RetryCount == 0)
- {
- RetryCount = 5;
- return {};
- }
- // Avoid flooding with requests while WAAPI is unavailable.
- FPlatformProcess::Sleep(RetrySleepTimeSeconds);
- }
- }
- #if PLATFORM_MAC
- if(ProjectPath.StartsWith(TEXT("Y:")))
- {
- ProjectPath.ReplaceInline(TEXT("Y:"), *FPlatformMisc::GetEnvironmentVariable(TEXT("HOME")));
- }
- if(ProjectPath.StartsWith(TEXT("Z:")))
- {
- ProjectPath.ReplaceInline(TEXT("Z:"), *FPlatformMisc::GetEnvironmentVariable(TEXT("ROOT")));
- }
- ProjectPath.ReplaceInline(TEXT("\\"), TEXT("/"));
- #endif
- return ProjectPath;
- }
- /** Checks if the currently loaded Wwise project matches the project path set in AkSettings (Wwise plugin settings).
- * NOTE: This function will block while Wwise has a modal window open. It should not be called on the Game thread.
- */
- bool FAkWaapiClient::CheckProjectLoaded()
- {
- #if AK_SUPPORT_WAAPI
- if (g_AkWaapiClient == nullptr)
- return false;
- if (!g_AkWaapiClient->IsConnected())
- {
- g_AkWaapiClient->m_Impl->m_pConnectionHandler->ResetReconnectionDelay();
- return false;
- }
- if (const UAkSettings* AkSettings = GetDefault<UAkSettings>())
- {
- auto ProjectPathString = WwiseUnrealHelper::GetWwiseProjectPath();
- FString sCurrentlyLoadedProjectPath = GetAndWaitForCurrentProject(1.0f);
- if (FPaths::IsSamePath(sCurrentlyLoadedProjectPath, ProjectPathString))
- {
- return true;
- }
- }
- #endif
- return false;
- }
- void FAkWaapiClient::BroadcastConnectionLost()
- {
- #if AK_SUPPORT_WAAPI
- m_Impl->bProjectLoaded = false;
- OnConnectionLost.Broadcast();
- #endif
- }
- bool FAkWaapiClient::IsConnected()
- {
- #if AK_SUPPORT_WAAPI
- if (UNLIKELY(!g_AkWaapiClient->m_Impl->m_Client))
- {
- return false;
- }
- return m_Impl->m_Client->IsConnected();
- #else
- return false;
- #endif
- }
- bool FAkWaapiClient::AttemptConnection()
- {
- bIsWrongProjectLoaded = false;
- bool bConnected = false;
- #if AK_SUPPORT_WAAPI
- if (UNLIKELY(!g_AkWaapiClient->m_Impl->m_Client))
- {
- bConnected = false;
- }
- else if (const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>())
- {
- bConnected = m_Impl->m_Client->Connect(TCHAR_TO_UTF8(*AkSettingsPerUser->WaapiIPAddress), AkSettingsPerUser->WaapiPort);
- }
- else
- {
- bConnected = m_Impl->m_Client->Connect(WAAPI_LOCAL_HOST_IP_STRING, WAAPI_PORT);
- }
- if (bConnected)
- {
- bool bProjectLoaded = CheckProjectLoaded();
- if (!bProjectLoaded)
- {
- // We successfully connected, but the wrong project is open (or getting the project timed out). Disconnect.
- // We will attemps reconnection later.
- bIsWrongProjectLoaded = true;
- m_Impl->m_Client->Disconnect();
- bConnected = false;
- }
- m_Impl->bProjectLoaded = bProjectLoaded;
- }
- #endif
- return bConnected;
- }
- bool FAkWaapiClient::Subscribe(const char* in_uri, const FString& in_options, WampEventCallback in_callback,
- uint64& out_subscriptionId, FString& out_result, int in_iTimeoutMs /*= 500*/)
- {
- bool eResult = false;
- #if AK_SUPPORT_WAAPI
- std::string out_resultString("");
- if (IsConnected())
- {
- if (!m_Impl->bIsConnectionClosing)
- {
- // Call for the AK WAAPI method using string params.
- if (LIKELY(g_AkWaapiClient->m_Impl->m_Client))
- {
- FScopeLock Lock(&m_Impl->ClientSection);
- eResult = m_Impl->m_Client->Subscribe(in_uri, TCHAR_TO_UTF8(*in_options), &WampEventCallbacks, out_subscriptionId, out_resultString, in_iTimeoutMs);
- }
- if (eResult)
- {
- m_Impl->m_wampEventCallbackMap.Add(out_subscriptionId, in_callback);
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Subscription failed: %s"), *FString(UTF8_TO_TCHAR(out_resultString.c_str())));
- }
- out_result = FString(UTF8_TO_TCHAR(out_resultString.c_str()));
- }
- }
- else
- {
- if (m_Impl && m_Impl->m_pConnectionHandler)
- {
- m_Impl->m_pConnectionHandler->ResetReconnectionDelay();
- }
- }
- #endif
- return eResult;
- }
- bool FAkWaapiClient::Subscribe(const char* in_uri, const TSharedRef<FJsonObject>& in_options, WampEventCallback in_callback,
- uint64& out_subscriptionId, TSharedPtr<FJsonObject>& out_result, int in_iTimeoutMs /*= 500*/)
- {
- bool eResult = false;
- #if AK_SUPPORT_WAAPI
- FString in_optionsString = TEXT("");
- // Retrieve the options data string from the Json object.
- JsonObjectToString(in_options, in_optionsString);
- FString out_resultString(TEXT(""));
- // Call for the AK WAAPI method using string params.
- eResult = Subscribe(in_uri, in_optionsString, in_callback, out_subscriptionId, out_resultString, in_iTimeoutMs);
- if (!eResult)
- {
- // Deserialize a JSON object from the string.
- TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(out_resultString);
- if ((!FJsonSerializer::Deserialize(Reader, out_result) || !out_result.IsValid()) && IsConnected())
- {
- UE_LOG(LogAkAudio, Log, TEXT("Subscribe: Output result -> unable to deserialize the Json object from the string : %s"), *out_resultString);
- }
- }
- #endif
- return eResult;
- }
- bool FAkWaapiClient::Unsubscribe(const uint64_t& in_subscriptionId, FString& out_result, int in_iTimeoutMs /*= 500*/, bool in_bSilenceLog /*= false*/)
- {
- bool eResult = false;
- #if AK_SUPPORT_WAAPI
- if (IsConnected())
- {
- if (!m_Impl->bIsConnectionClosing)
- {
- std::string out_resultString("");
- // Call the AK WAAPI method.
- if (LIKELY(g_AkWaapiClient->m_Impl->m_Client))
- {
- FScopeLock Lock(&m_Impl->ClientSection);
- eResult = m_Impl->m_Client->Unsubscribe(in_subscriptionId, out_resultString, in_iTimeoutMs);
- }
- if (eResult)
- {
- if (m_Impl->m_wampEventCallbackMap.Contains(in_subscriptionId))
- m_Impl->m_wampEventCallbackMap.Remove(in_subscriptionId);
- }
- else if (!in_bSilenceLog)
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unsubscription failed: %s"), *FString(UTF8_TO_TCHAR(out_resultString.c_str())));
- }
- out_result = FString(UTF8_TO_TCHAR(out_resultString.c_str()));
- }
- }
- else
- {
- if (m_Impl && m_Impl->m_pConnectionHandler)
- {
- m_Impl->m_pConnectionHandler->ResetReconnectionDelay();
- }
- }
- #endif
- return eResult;
- }
- bool FAkWaapiClient::Unsubscribe(const uint64_t& in_subscriptionId, TSharedPtr<FJsonObject>& out_result, int in_iTimeoutMs /*= 500*/, bool in_bSilenceLog /*= false*/)
- {
- bool eResult = false;
- #if AK_SUPPORT_WAAPI
- if (IsConnected())
- {
- FString out_resultString(TEXT(""));
- // Call the AK WAAPI method.
- eResult = Unsubscribe(in_subscriptionId, out_resultString, in_iTimeoutMs, in_bSilenceLog);
- if (!eResult)
- {
- // Deserialize a JSON object from the string
- TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(out_resultString);
- if ((!FJsonSerializer::Deserialize(Reader, out_result) || !out_result.IsValid()) && IsConnected())
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unsubscribe: Output result -> unable to deserialize the Json object from the string : %s"), *out_resultString);
- }
- }
- }
- else
- {
- if (m_Impl && m_Impl->m_pConnectionHandler)
- {
- m_Impl->m_pConnectionHandler->ResetReconnectionDelay();
- }
- }
- #endif
- return eResult;
- }
- bool FAkWaapiClient::RemoveWampEventCallback(const uint64_t in_subscriptionId)
- {
- #if AK_SUPPORT_WAAPI
- if (m_Impl->m_wampEventCallbackMap.Contains(in_subscriptionId))
- {
- m_Impl->m_wampEventCallbackMap.Remove(in_subscriptionId);
- return true;
- }
- #endif
- return false;
- }
- bool FAkWaapiClient::Call(const char* in_uri, const FString& in_args, const FString& in_options, FString& out_result, int in_iTimeoutMs /*= 500*/, bool silenceLog /* = false*/)
- {
- bool eResult = false;
- #if AK_SUPPORT_WAAPI
- if (IsConnected())
- {
- if (!m_Impl->bIsConnectionClosing)
- {
- std::string out_resultString("");
- // Call the AK WAAPI method.
- if (LIKELY(g_AkWaapiClient->m_Impl->m_Client))
- {
- FScopeLock Lock(&m_Impl->ClientSection);
- eResult = m_Impl->m_Client->Call(in_uri, TCHAR_TO_UTF8(*in_args), TCHAR_TO_UTF8(*in_options), out_resultString, in_iTimeoutMs);
- }
- if (!eResult && !silenceLog)
- {
- UE_LOG(LogAkAudio, Log, TEXT("Call failed: %s"), *FString(UTF8_TO_TCHAR(out_resultString.c_str())));
- }
- out_result = FString(UTF8_TO_TCHAR(out_resultString.c_str()));
- }
- }
- else
- {
- if (m_Impl && m_Impl->m_pConnectionHandler)
- {
- m_Impl->m_pConnectionHandler->ResetReconnectionDelay();
- }
- }
- #endif
- return eResult;
- }
- bool FAkWaapiClient::Call(const char* in_uri, const TSharedRef<FJsonObject>& in_args, const TSharedRef<FJsonObject>& in_options,
- TSharedPtr<FJsonObject>& out_result, int in_iTimeoutMs /*= 500*/, bool silenceLog /*= false*/)
- {
- bool eResult = false;
- #if AK_SUPPORT_WAAPI
- FString in_argsString = TEXT("");
- FString in_optionsString = TEXT("");
- // Make sure the arguments are valid Json data.
- JsonObjectToString(in_args, in_argsString);
- // Make sure the options are valid Json data.
- JsonObjectToString(in_options, in_optionsString);
- FString out_resultString(TEXT(""));
- // Call the AK WAAPI method.
- eResult = Call(in_uri, in_argsString, in_optionsString, out_resultString, in_iTimeoutMs, silenceLog);
- // Deserialize a JSON object from the string.
- TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(out_resultString);
- if (!FJsonSerializer::Deserialize(Reader, out_result) || !out_result.IsValid())
- {
- if (!silenceLog && IsConnected())
- {
- UE_LOG(LogAkAudio, Log, TEXT("Output result -> unable to deserialize a JSON object from the string : %s"), *out_resultString);
- }
- }
- #endif
- return eResult;
- }
- bool FAkWaapiClient::Call(const char* inUri, const TArray<KeyValueArgs>& Values,
- TSharedPtr<FJsonObject>& outJsonResult)
- {
- TSharedRef<FJsonObject> Args = MakeShareable(new FJsonObject());
- for (const auto& Value : Values)
- {
- Args->SetStringField(Value.KeyArg, Value.ValueArg);
- }
- // Construct the options Json object;
- TSharedRef<FJsonObject> Options = MakeShareable(new FJsonObject());
- // Request infos/changes in Waapi Picker using WAAPI
- if (Call(inUri, Args, Options, outJsonResult))
- {
- return true;
- }
- UE_LOG(LogAkAudio, Log, TEXT("Call %hs failed."), inUri);
- return false;
- }
- FAkWaapiClient::FAkWaapiClient()
- : m_Impl(new FAkWaapiClientImpl)
- {
- }
- /** Sets in_outParentGUID to the object ID of a parent of object in_objectGUID of type in_strType. */
- void FAkWaapiClient::GetParentOfType(FGuid in_objectGUID, FGuid& in_outParentGUID, FString in_strType)
- {
- #if AK_SUPPORT_WAAPI
- if (g_AkWaapiClient == nullptr)
- return;
- /* Construct the relevant WAAPI json fields. */
- AkInt64 returnFlags = (AkInt64)WAAPIGetReturnOptionFlag::ID |
- (AkInt64)WAAPIGetReturnOptionFlag::TYPE;
- TArray<TSharedPtr<FJsonValue>> fromID;
- fromID.Add(MakeShareable(new FJsonValueString(in_objectGUID.ToString(EGuidFormats::DigitsWithHyphensInBraces))));
- TSharedPtr<FJsonObject> outJsonResult;
- if (!WAAPIGet(WAAPIGetFromOption::ID, fromID, returnFlags, outJsonResult))
- return;
- if (!outJsonResult->HasField(WAAPIStrings::RETURN))
- return;
- TArray<TSharedPtr<FJsonValue>> returnJson = outJsonResult->GetArrayField(WAAPIStrings::RETURN);
- if (returnJson.Num() <= 0)
- return;
- FString objectType;
- {
- TSharedPtr<FJsonObject> typeObject = returnJson[0]->AsObject();
- if (typeObject->HasField(WAAPIStrings::TYPE))
- objectType = typeObject->GetStringField(WAAPIStrings::TYPE);
- }
- in_outParentGUID = in_objectGUID;
- if (objectType.Equals(in_strType, ESearchCase::IgnoreCase))
- return;
- TSharedPtr<FJsonObject> select = MakeShareable(new FJsonObject());
- TArray<TSharedPtr<FJsonValue>> selectJsonArray;
- selectJsonArray.Add(MakeShareable(new FJsonValueString(WAAPIStrings::PARENT)));
- select->SetArrayField(WAAPIStrings::SELECT, selectJsonArray);
- TArray<TSharedPtr<FJsonValue>> transform;
- transform.Add(MakeShareable(new FJsonValueObject(select)));
- while (!objectType.Equals(in_strType, ESearchCase::IgnoreCase))
- {
- fromID.Empty();
- fromID.Add(MakeShareable(new FJsonValueString(in_outParentGUID.ToString(EGuidFormats::DigitsWithHyphensInBraces))));
- outJsonResult = MakeShareable(new FJsonObject());
- if (!WAAPIGet(WAAPIGetFromOption::ID, fromID, returnFlags, outJsonResult, WAAPIGetTransformOption::SELECT, selectJsonArray))
- break;
- if (!outJsonResult->HasField(WAAPIStrings::RETURN))
- continue;
- TArray<TSharedPtr<FJsonValue>> aReturnJson = outJsonResult->GetArrayField(WAAPIStrings::RETURN);
- TSharedPtr<FJsonObject> returnObject = aReturnJson[0]->AsObject();
- if (returnObject->HasField(WAAPIStrings::TYPE))
- objectType = returnObject->GetStringField(WAAPIStrings::TYPE);
- if (returnObject->HasField(WAAPIStrings::ID))
- FGuid::Parse(returnObject->GetStringField(WAAPIStrings::ID), in_outParentGUID);
- }
- #endif
- }
- bool FAkWaapiClient::IsProjectDirty()
- {
- #if AK_SUPPORT_WAAPI
- checkf(g_AkWaapiClient != nullptr, TEXT("g_AkWaapiClient is nullptr. Make sure Initialize is called!"));
- TArray<TSharedPtr<FJsonValue>> inFromItems;
- AkInt64 iReturnOptions = (uint64_t)WAAPIGetReturnOptionFlag::WORKUNIT_IS_DIRTY;
- TSharedPtr<FJsonObject> pJsonResult = MakeShareable(new FJsonObject());
- inFromItems.Add(MakeShareable(new FJsonValueString("WorkUnit")));
- WAAPIGet(WAAPIGetFromOption::OF_TYPE, inFromItems, iReturnOptions, pJsonResult);
- if (pJsonResult->HasField(WAAPIStrings::RETURN))
- {
- TArray<TSharedPtr<FJsonValue>> returnJson = pJsonResult->GetArrayField(WAAPIStrings::RETURN);
- FString workunitDirty = GetReturnOptionString(WAAPIGetReturnOptionFlag::WORKUNIT_IS_DIRTY);
- for (auto json : returnJson)
- {
- if (json->AsObject()->HasField(workunitDirty) && json->AsObject()->GetBoolField(workunitDirty))
- return true;
- }
- }
- #endif
- return false;
- }
- /**
- * WAAPI Structures
- */
- FString FAkWaapiClient::GetFromOptionString(WAAPIGetFromOption from)
- {
- switch (from)
- {
- case WAAPIGetFromOption::ID: return "id";
- case WAAPIGetFromOption::SEARCH: return "search";
- case WAAPIGetFromOption::PATH: return "path";
- case WAAPIGetFromOption::OF_TYPE: return "ofType";
- case WAAPIGetFromOption::QUERY: return "query";
- default: checkf(false, TEXT("From option unhandled")); return "";
- }
- }
- FString FAkWaapiClient::GetTransformOptionString(WAAPIGetTransformOption transform)
- {
- switch (transform)
- {
- case WAAPIGetTransformOption::SELECT: return "select";
- case WAAPIGetTransformOption::RANGE: return "range";
- case WAAPIGetTransformOption::WHERE: return "where";
- case WAAPIGetTransformOption::NONE: return "";
- default: checkf(false, TEXT("Transform option unhandled")); return "";
- }
- }
- FAkWaapiClient::WAAPIGetReturnOptionFlag FAkWaapiClient::GetReturnOptionFlagValue(int in_iFlagIndex)
- {
- return (WAAPIGetReturnOptionFlag)(AkInt64)pow(2, in_iFlagIndex);
- }
- FString FAkWaapiClient::GetReturnOptionString(WAAPIGetReturnOptionFlag returnOption)
- {
- switch (returnOption)
- {
- case WAAPIGetReturnOptionFlag::ID: return "id";
- case WAAPIGetReturnOptionFlag::NAME: return "name";
- case WAAPIGetReturnOptionFlag::NOTES: return "notes";
- case WAAPIGetReturnOptionFlag::TYPE: return "type";
- case WAAPIGetReturnOptionFlag::PATH: return "path";
- case WAAPIGetReturnOptionFlag::PARENT: return "parent";
- case WAAPIGetReturnOptionFlag::OWNER: return "owner";
- case WAAPIGetReturnOptionFlag::IS_PLAYABLE: return "isPlayable";
- case WAAPIGetReturnOptionFlag::SHORT_ID: return "shortId";
- case WAAPIGetReturnOptionFlag::CATEGORY: return "category";
- case WAAPIGetReturnOptionFlag::FILEPATH: return "filePath";
- case WAAPIGetReturnOptionFlag::WORKUNIT: return "workunit";
- case WAAPIGetReturnOptionFlag::CHILDREN_COUNT: return "childrenCount";
- case WAAPIGetReturnOptionFlag::MUSIC_TRANSITION_ROOT: return "music:transitionRoot";
- case WAAPIGetReturnOptionFlag::MUSIC_PLAYLIST_ROOT: return "music:playlistRoot";
- case WAAPIGetReturnOptionFlag::SOUND_ORIGINAL_WAV_FILE_PATH: return "sound:originalWavFilePath";
- case WAAPIGetReturnOptionFlag::SOUND_CONVERTED_WEM_FILE_PATH: return "sound:convertedWemFilePath";
- case WAAPIGetReturnOptionFlag::SOUNDBANK_BANK_FILE_PATH: return "soundbank:bnkFilePath";
- case WAAPIGetReturnOptionFlag::AUDIO_SOURCE_PLAYBACK_DURATION: return "audioSource:playbackDuration";
- case WAAPIGetReturnOptionFlag::AUDIO_SOURCE_MAX_DURATION_SOURCE: return "audioSource:maxDurationSource";
- case WAAPIGetReturnOptionFlag::AUDIO_SOURCE_TRIM_VALUES: return "audioSource:trimValues";
- case WAAPIGetReturnOptionFlag::WORKUNIT_IS_DEFAULT: return "workunit:isDefault";
- case WAAPIGetReturnOptionFlag::WORKUNIT_TYPE: return "workunit:type";
- case WAAPIGetReturnOptionFlag::WORKUNIT_IS_DIRTY: return "workunit:isDirty";
- default: checkf(false, TEXT("Return option unhandled")); return "";
- }
- }
- /**
- * JSon Helpers
- */
- TSharedRef<FJsonObject> FAkWaapiClient::CreateWAAPIGetArgumentJson(WAAPIGetFromOption in_FromOption, TArray<TSharedPtr<FJsonValue>> in_FromItems,
- WAAPIGetTransformOption in_TransformOption /*= WAAPIGetTransformOption::NONE*/,
- TArray<TSharedPtr<FJsonValue>> in_TransformItems /*= TArray<TSharedPtr<FJsonValue>>()*/)
- {
- TSharedRef<FJsonObject> args = MakeShareable(new FJsonObject());
- TSharedPtr<FJsonObject> from = MakeShareable(new FJsonObject());
- from->SetArrayField(GetFromOptionString(in_FromOption), in_FromItems);
- args->SetObjectField(FAkWaapiClient::WAAPIStrings::FROM, from);
- if (in_TransformOption != WAAPIGetTransformOption::NONE && in_TransformItems.Num() > 0)
- {
- TArray<TSharedPtr<FJsonValue>> transformArgArray;
- TSharedPtr<FJsonObject> transformObjectArg = MakeShareable(new FJsonObject());
- transformObjectArg->SetArrayField(GetTransformOptionString(in_TransformOption), in_TransformItems);
- transformArgArray.Add(MakeShareable(new FJsonValueObject(transformObjectArg)));
- args->SetArrayField(FAkWaapiClient::WAAPIStrings::TRANSFORM, transformArgArray);
- }
- return args;
- }
- TSharedRef<FJsonObject> FAkWaapiClient::CreateWAAPIGetReturnOptionsJson(AkInt64 ReturnOptions)
- {
- TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
- TArray<TSharedPtr<FJsonValue>> StructJsonArray;
- for (int bitIndex = 0; bitIndex < (int)WAAPIGetReturnOptionFlag::NUM_FLAGS; ++bitIndex)
- {
- WAAPIGetReturnOptionFlag returnOption = GetReturnOptionFlagValue(bitIndex);
- if ((ReturnOptions & (AkInt64)returnOption) != 0)
- {
- StructJsonArray.Add(MakeShareable(new FJsonValueString(GetReturnOptionString(returnOption))));
- }
- }
- options->SetArrayField(FAkWaapiClient::WAAPIStrings::RETURN, StructJsonArray);
- return options;
- }
- /**
- * WAAPI Helpers
- */
- bool FAkWaapiClient::WAAPIGet(WAAPIGetFromOption inFromField,
- TArray<TSharedPtr<FJsonValue>> inFromItems,
- AkInt64 inReturnOptionsFlags,
- TSharedPtr<FJsonObject>& outJsonResult,
- WAAPIGetTransformOption inTransformField /*= WAAPIGetTransformOption::NONE*/,
- TArray<TSharedPtr<FJsonValue>> inTransformItems /*= TArray<TSharedPtr<FJsonValue>>()*/,
- bool in_bSilenceLog /*= false*/)
- {
- #if AK_SUPPORT_WAAPI
- TSharedRef<FJsonObject> getArgsJson = CreateWAAPIGetArgumentJson(inFromField, inFromItems, inTransformField, inTransformItems);
- TSharedRef<FJsonObject> returnOptionsJson = CreateWAAPIGetReturnOptionsJson(inReturnOptionsFlags);
- if (g_AkWaapiClient != nullptr && g_AkWaapiClient->IsConnected())
- {
- if (g_AkWaapiClient->Call(ak::wwise::core::object::get, getArgsJson, returnOptionsJson, outJsonResult, 500, in_bSilenceLog))
- return true;
- else if (!in_bSilenceLog)
- UE_LOG(LogAkAudio, Log, TEXT("Call to ak.wwise.core.object.get Failed"));
- }
- #endif
- return false;
- }
- bool FAkWaapiClient::GetGUIDForObjectOfTypeWithName(FGuid& io_GUID, const FString& in_sTypeName, const FString& in_sName)
- {
- #if AK_SUPPORT_WAAPI
- TArray<TSharedPtr<FJsonValue>> nameArray;
- nameArray.Add(MakeShareable(new FJsonValueString(in_sName)));
- TSharedPtr<FJsonObject> outJsonResult = MakeShareable(new FJsonObject());
- AkInt64 returnOptionFlags = (AkInt64)WAAPIGetReturnOptionFlag::ID | (AkInt64)WAAPIGetReturnOptionFlag::NAME | (AkInt64)WAAPIGetReturnOptionFlag::TYPE;
- if (WAAPIGet(WAAPIGetFromOption::SEARCH, nameArray, returnOptionFlags, outJsonResult))
- {
- if (outJsonResult->HasField(WAAPIStrings::RETURN))
- {
- TArray<TSharedPtr<FJsonValue>> returnJson = outJsonResult->GetArrayField(WAAPIStrings::RETURN);
- for (auto json : returnJson)
- {
- auto jsonObj = json->AsObject();
- auto name = jsonObj->GetStringField(WAAPIStrings::NAME);
- auto typeName = jsonObj->GetStringField(WAAPIStrings::TYPE);
- if (name == in_sName && typeName.Equals(in_sTypeName, ESearchCase::IgnoreCase))
- {
- auto iD = jsonObj->GetStringField(WAAPIStrings::ID);
- FGuid::Parse(iD, io_GUID);
- return true;
- }
- }
- }
- }
- #endif
- return false;
- }
- void FAkWaapiClient::SaveProject()
- {
- #if AK_SUPPORT_WAAPI
- TSharedRef<FJsonObject> argsJson = MakeShareable(new FJsonObject());
- TSharedRef<FJsonObject> optionsJson = MakeShareable(new FJsonObject());
- TSharedPtr<FJsonObject> outputJson = MakeShareable(new FJsonObject());
- if (g_AkWaapiClient->IsConnected())
- {
- g_AkWaapiClient->Call(ak::wwise::core::project::save, argsJson, optionsJson, outputJson);
- }
- #endif
- }
- const FString FAkWaapiClient::WAAPIStrings::BACK_SLASH = TEXT("\\");
- const FString FAkWaapiClient::WAAPIStrings::ID = TEXT("id");
- const FString FAkWaapiClient::WAAPIStrings::RETURN = TEXT("return");
- const FString FAkWaapiClient::WAAPIStrings::PATH = TEXT("path");
- const FString FAkWaapiClient::WAAPIStrings::FILEPATH = TEXT("filePath");
- const FString FAkWaapiClient::WAAPIStrings::FROM = TEXT("from");
- const FString FAkWaapiClient::WAAPIStrings::NAME = TEXT("name");
- const FString FAkWaapiClient::WAAPIStrings::TYPE = TEXT("type");
- const FString FAkWaapiClient::WAAPIStrings::CHILDREN = TEXT("children");
- const FString FAkWaapiClient::WAAPIStrings::CHILDREN_COUNT = TEXT("childrenCount");
- const FString FAkWaapiClient::WAAPIStrings::ANCESTORS = TEXT("ancestors");
- const FString FAkWaapiClient::WAAPIStrings::DESCENDANTS = TEXT("descendants");
- const FString FAkWaapiClient::WAAPIStrings::WORKUNIT_TYPE = TEXT("workunit:type");
- const FString FAkWaapiClient::WAAPIStrings::FOLDER = TEXT("Folder");
- const FString FAkWaapiClient::WAAPIStrings::PHYSICAL_FOLDER = TEXT("PhysicalFolder");
- const FString FAkWaapiClient::WAAPIStrings::SEARCH = TEXT("search");
- const FString FAkWaapiClient::WAAPIStrings::PARENT = TEXT("parent");
- const FString FAkWaapiClient::WAAPIStrings::SELECT = TEXT("select");
- const FString FAkWaapiClient::WAAPIStrings::TRANSFORM = TEXT("transform");
- const FString FAkWaapiClient::WAAPIStrings::OBJECT = TEXT("object");
- const FString FAkWaapiClient::WAAPIStrings::OBJECTS = TEXT("objects");
- const FString FAkWaapiClient::WAAPIStrings::VALUE = TEXT("value");
- const FString FAkWaapiClient::WAAPIStrings::COMMAND = TEXT("command");
- const FString FAkWaapiClient::WAAPIStrings::TRANSPORT = TEXT("transport");
- const FString FAkWaapiClient::WAAPIStrings::ACTION = TEXT("action");
- const FString FAkWaapiClient::WAAPIStrings::PLAY = TEXT("play");
- const FString FAkWaapiClient::WAAPIStrings::STOP = TEXT("stop");
- const FString FAkWaapiClient::WAAPIStrings::STOPPED = TEXT("stopped");
- const FString FAkWaapiClient::WAAPIStrings::DISPLAY_NAME = TEXT("displayName");
- const FString FAkWaapiClient::WAAPIStrings::DELETE_ITEMS = TEXT("Delete Items");
- const FString FAkWaapiClient::WAAPIStrings::DRAG_DROP_ITEMS = TEXT("Drag Drop Items");
- const FString FAkWaapiClient::WAAPIStrings::UNDO = TEXT("Undo");
- const FString FAkWaapiClient::WAAPIStrings::REDO = TEXT("Redo");
- const FString FAkWaapiClient::WAAPIStrings::STATE = TEXT("state");
- const FString FAkWaapiClient::WAAPIStrings::OF_TYPE = TEXT("ofType");
- const FString FAkWaapiClient::WAAPIStrings::PROJECT = TEXT("Project");
- const FString FAkWaapiClient::WAAPIStrings::PROPERTY = TEXT("property");
- const FString FAkWaapiClient::WAAPIStrings::VOLUME = TEXT("Volume");
- const FString FAkWaapiClient::WAAPIStrings::FIND_IN_PROJECT_EXPLORER = TEXT("FindInProjectExplorerSelectionChannel1");
- const FString FAkWaapiClient::WAAPIStrings::TRIMMED_DURATION = TEXT("trimmedDuration");
- const FString FAkWaapiClient::WwiseTypeStrings::SOUND = TEXT("Sound");
- const FString FAkWaapiClient::WwiseTypeStrings::WORKUNIT = TEXT("WorkUnit");
- const FString FAkWaapiClient::AudioPeaksStrings::Args::OBJECT = TEXT("object");
- const FString FAkWaapiClient::AudioPeaksStrings::Args::NUM_PEAKS = TEXT("numPeaks");
- const FString FAkWaapiClient::AudioPeaksStrings::Args::TIME_FROM = TEXT("timeFrom");
- const FString FAkWaapiClient::AudioPeaksStrings::Args::TIME_TO = TEXT("timeTo");
- const FString FAkWaapiClient::AudioPeaksStrings::Args::CROSS_CHANNEL_PEAKS = TEXT("getCrossChannelPeaks");
- const FString FAkWaapiClient::AudioPeaksStrings::Results::PEAKS_BINARY = TEXT("peaksBinaryStrings");
- const FString FAkWaapiClient::AudioPeaksStrings::Results::MAX_ABS_VALUE = TEXT("maxAbsValue");
- const FString FAkWaapiClient::AudioPeaksStrings::Results::PEAKS_ARRAY_LENGTH = TEXT("peaksArrayLength");
- const FString FAkWaapiClient::AudioPeaksStrings::Results::PEAKS_DATA_SIZE = TEXT("peaksDataSize");
- const FString FAkWaapiClient::PropertyChangedStrings::RequiredOptions::OBJECT = TEXT("object");
- const FString FAkWaapiClient::PropertyChangedStrings::RequiredOptions::PROPERTY = TEXT("property");
- const FString FAkWaapiClient::PropertyChangedStrings::OptionalOptions::RETURN = TEXT("return");
- const FString FAkWaapiClient::PropertyChangedStrings::OptionalOptions::PLATFORM = TEXT("platform");
- const FString FAkWaapiClient::AudioSourceProperties::TRIM_END = TEXT("TrimEnd");
- const FString FAkWaapiClient::AudioSourceProperties::TRIM_BEGIN = TEXT("TrimBegin");
- const FString FAkWaapiClient::PlaybackDurationStrings::MIN = TEXT("playbackDurationMin");
- const FString FAkWaapiClient::PlaybackDurationStrings::MAX = TEXT("playbackDurationMax");
- const FString FAkWaapiClient::PlaybackDurationStrings::TYPE = TEXT("playbackDurationType");
- const FString FAkWaapiClient::TrimValuesStrings::TRIM_BEGIN = TEXT("trimBegin");
- const FString FAkWaapiClient::TrimValuesStrings::TRIM_END = TEXT("trimEnd");
- // end
|