/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include #include #include #include #include #include #include #include namespace Audio { extern CAudioLogger g_audioLogger; /////////////////////////////////////////////////////////////////////////////////////////////////// // CAudioThread /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// CAudioThread::~CAudioThread() { Deactivate(); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioThread::Run() { AZ_Assert(m_audioSystem, "Audio Thread has no Audio System to run!\n"); m_running = true; while (m_running) { m_audioSystem->InternalUpdate(); } } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioThread::Activate(CAudioSystem* const audioSystem) { m_audioSystem = audioSystem; AZStd::thread_desc threadDesc; threadDesc.m_name = "Audio Thread"; threadDesc.m_cpuId = AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY; auto threadFunc = AZStd::bind(&CAudioThread::Run, this); m_thread = AZStd::thread(threadFunc, &threadDesc); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioThread::Deactivate() { if (m_running) { m_running = false; m_thread.join(); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // CAudioSystem /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// CAudioSystem::CAudioSystem() : m_bSystemInitialized(false) { m_apAudioProxies.reserve(g_audioCVars.m_nAudioObjectPoolSize); m_apAudioProxiesToBeFreed.reserve(16); AudioSystemRequestBus::Handler::BusConnect(); AudioSystemThreadSafeRequestBus::Handler::BusConnect(); AudioSystemInternalRequestBus::Handler::BusConnect(); } /////////////////////////////////////////////////////////////////////////////////////////////////// CAudioSystem::~CAudioSystem() { AudioSystemRequestBus::Handler::BusDisconnect(); AudioSystemThreadSafeRequestBus::Handler::BusDisconnect(); AudioSystemInternalRequestBus::Handler::BusDisconnect(); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::PushRequest(const SAudioRequest& audioRequestData) { CAudioRequestInternal request(audioRequestData); AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::PushRequest - called from non-Main thread!"); AZ_Assert(0 == (request.nFlags & eARF_THREAD_SAFE_PUSH), "AudioSystem::PushRequest - called with flag THREAD_SAFE_PUSH!"); AZ_Assert(0 == (request.nFlags & eARF_EXECUTE_BLOCKING), "AudioSystem::PushRequest - called with flag EXECUTE_BLOCKING!"); AudioSystemInternalRequestBus::QueueBroadcast(&AudioSystemInternalRequestBus::Events::ProcessRequestByPriority, request); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::PushRequestBlocking(const SAudioRequest& audioRequestData) { // Main Thread! AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); CAudioRequestInternal request(audioRequestData); AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::PushRequestBlocking - called from non-Main thread!"); AZ_Assert(0 != (request.nFlags & eARF_EXECUTE_BLOCKING), "AudioSystem::PushRequestBlocking - called without EXECUTE_BLOCKING flag!"); AZ_Assert(0 == (request.nFlags & eARF_THREAD_SAFE_PUSH), "AudioSystem::PushRequestBlocking - called with THREAD_SAFE_PUSH flag!"); ProcessRequestBlocking(request); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::PushRequestThreadSafe(const SAudioRequest& audioRequestData) { CAudioRequestInternal request(audioRequestData); AZ_Assert(0 != (request.nFlags & eARF_THREAD_SAFE_PUSH), "AudioSystem::PushRequestThreadSafe - called without THREAD_SAFE_PUSH flag!"); AZ_Assert(0 == (request.nFlags & eARF_EXECUTE_BLOCKING), "AudioSystem::PushRequestThreadSafe - called with flag EXECUTE_BLOCKING!"); AudioSystemThreadSafeRequestBus::QueueFunction(AZStd::bind(&CAudioSystem::ProcessRequestThreadSafe, this, request)); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::AddRequestListener( AudioRequestCallbackType func, void* const callbackOwner, const EAudioRequestType requestType, const TATLEnumFlagsType specificRequestMask) { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::AddRequestListener - called from a non-Main thread!"); if (func) { SAudioEventListener listener; listener.m_callbackOwner = callbackOwner; listener.m_fnOnEvent = func; listener.m_requestType = requestType; listener.m_specificRequestMask = specificRequestMask; m_oATL.AddRequestListener(listener); } } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::RemoveRequestListener(AudioRequestCallbackType func, void* const callbackOwner) { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::RemoveRequestListener - called from a non-Main thread!"); SAudioEventListener listener; listener.m_callbackOwner = callbackOwner; listener.m_fnOnEvent = func; m_oATL.RemoveRequestListener(listener); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::ExternalUpdate() { // Main Thread! AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::ExternalUpdate - called from non-Main thread!"); // Notify callbacks on the pending callbacks queue... // These are requests that were completed then queued for callback processing to happen here. ExecuteRequestCompletionCallbacks(m_pendingCallbacksQueue, m_pendingCallbacksMutex); // Notify callbacks from the "thread safe" queue... ExecuteRequestCompletionCallbacks(m_threadSafeCallbacksQueue, m_threadSafeCallbacksMutex, true); // Other notifications to be sent out... AudioTriggerNotificationBus::ExecuteQueuedEvents(); // Free any Audio Proxies that are queued up for deletion... for (auto audioProxy : m_apAudioProxiesToBeFreed) { azdestroy(audioProxy, Audio::AudioSystemAllocator); } m_apAudioProxiesToBeFreed.clear(); #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) DrawAudioDebugData(); #endif // INCLUDE_AUDIO_PRODUCTION_CODE } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::InternalUpdate() { // Audio Thread! AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); auto startUpdateTime = AZStd::chrono::system_clock::now(); // stamp the start time bool handledBlockingRequests = false; { AZStd::lock_guard lock(m_blockingRequestsMutex); handledBlockingRequests = ProcessRequests(m_blockingRequestsQueue); } if (!handledBlockingRequests) { // Call the ProcessRequestByPriority events queued up... AudioSystemInternalRequestBus::ExecuteQueuedEvents(); } // Call the ProcessRequestThreadSafe events queued up... AudioSystemThreadSafeRequestBus::ExecuteQueuedEvents(); m_oATL.Update(); #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) #if defined(PROVIDE_GETNAME_SUPPORT) { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::Audio, "Sync Debug Name Changes"); AZStd::lock_guard lock(m_debugNameStoreMutex); m_debugNameStore.SyncChanges(m_oATL.GetDebugStore()); } #endif // PROVIDE_GETNAME_SUPPORT #endif // INCLUDE_AUDIO_PRODUCTION_CODE if (!handledBlockingRequests) { auto endUpdateTime = AZStd::chrono::system_clock::now(); // stamp the end time auto elapsedUpdateTime = AZStd::chrono::duration_cast(endUpdateTime - startUpdateTime); if (elapsedUpdateTime < m_targetUpdatePeriod) { AZ_PROFILE_SCOPE_IDLE(AZ::Debug::ProfileCategory::Audio, "Wait Remaining Time in Update Period"); m_processingEvent.try_acquire_for(m_targetUpdatePeriod - elapsedUpdateTime); } } } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystem::Initialize() { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::Initialize - called from a non-Main thread!"); if (!m_bSystemInitialized) { m_audioSystemThread.Deactivate(); m_oATL.Initialize(); m_audioSystemThread.Activate(this); for (int i = 0; i < g_audioCVars.m_nAudioObjectPoolSize; ++i) { auto audioProxy = azcreate(CAudioProxy, (), Audio::AudioSystemAllocator, "AudioProxy"); m_apAudioProxies.push_back(audioProxy); } m_bSystemInitialized = true; } return m_bSystemInitialized; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::Release() { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::Release - called from a non-Main thread!"); for (auto audioProxy : m_apAudioProxies) { azdestroy(audioProxy, Audio::AudioSystemAllocator); } for (auto audioProxy : m_apAudioProxiesToBeFreed) { azdestroy(audioProxy, Audio::AudioSystemAllocator); } m_apAudioProxies.clear(); m_apAudioProxiesToBeFreed.clear(); // Release the audio implementation... SAudioRequest request; SAudioManagerRequestData requestData; request.nFlags = (eARF_PRIORITY_HIGH | eARF_EXECUTE_BLOCKING); request.pData = &requestData; PushRequestBlocking(request); m_audioSystemThread.Deactivate(); const bool bSuccess = m_oATL.ShutDown(); m_bSystemInitialized = false; } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioControlID CAudioSystem::GetAudioTriggerID(const char* const sAudioTriggerName) const { return m_oATL.GetAudioTriggerID(sAudioTriggerName); } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioControlID CAudioSystem::GetAudioRtpcID(const char* const sAudioRtpcName) const { return m_oATL.GetAudioRtpcID(sAudioRtpcName); } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioControlID CAudioSystem::GetAudioSwitchID(const char* const sAudioStateName) const { return m_oATL.GetAudioSwitchID(sAudioStateName); } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioSwitchStateID CAudioSystem::GetAudioSwitchStateID(const TAudioControlID nSwitchID, const char* const sAudioSwitchStateName) const { return m_oATL.GetAudioSwitchStateID(nSwitchID, sAudioSwitchStateName); } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioPreloadRequestID CAudioSystem::GetAudioPreloadRequestID(const char* const sAudioPreloadRequestName) const { return m_oATL.GetAudioPreloadRequestID(sAudioPreloadRequestName); } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioEnvironmentID CAudioSystem::GetAudioEnvironmentID(const char* const sAudioEnvironmentName) const { return m_oATL.GetAudioEnvironmentID(sAudioEnvironmentName); } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystem::ReserveAudioListenerID(TAudioObjectID& rAudioObjectID) { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::ReserveAudioListenerID - called from a non-Main thread!"); return m_oATL.ReserveAudioListenerID(rAudioObjectID); } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystem::ReleaseAudioListenerID(TAudioObjectID const nAudioObjectID) { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::ReleaseAudioListenerID - called from a non-Main thread!"); return m_oATL.ReleaseAudioListenerID(nAudioObjectID); } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystem::SetAudioListenerOverrideID(const TAudioObjectID nAudioObjectID) { return m_oATL.SetAudioListenerOverrideID(nAudioObjectID); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::GetInfo(SAudioSystemInfo& rAudioSystemInfo) { //TODO: } /////////////////////////////////////////////////////////////////////////////////////////////////// const char* CAudioSystem::GetControlsPath() const { // this shouldn't get called before UpdateControlsPath has been called. AZ_WarningOnce("AudioSystem", !m_controlsPath.empty(), "AudioSystem::GetControlsPath - controls path has been requested before it has been set!"); return m_controlsPath.c_str(); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::UpdateControlsPath() { AZStd::string controlsPath("libs/gameaudio/"); controlsPath += m_oATL.GetControlsImplSubPath(); if (AZ::StringFunc::RelativePath::Normalize(controlsPath)) { m_controlsPath = controlsPath.c_str(); } else { g_audioLogger.Log(eALT_ERROR, "AudioSystem::UpdateControlsPath - failed to normalize the controls path '%s'!", controlsPath.c_str()); } } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::RefreshAudioSystem(const char* const levelName) { #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::RefreshAudioSystem - called from a non-Main thread!"); // Get the controls path and a level-specific preload Id first. // This will be passed with the request so that it doesn't have to lookup this data // and punch the AudioSystemRequestBus from the Audio Thread. const char* audioControlsPath = nullptr; Audio::AudioSystemRequestBus::BroadcastResult(audioControlsPath, &Audio::AudioSystemRequestBus::Events::GetControlsPath); Audio::TAudioPreloadRequestID levelPreloadId = INVALID_AUDIO_PRELOAD_REQUEST_ID; if (levelName && levelName[0] != '\0') { Audio::AudioSystemRequestBus::BroadcastResult(levelPreloadId, &Audio::AudioSystemRequestBus::Events::GetAudioPreloadRequestID, levelName); } Audio::SAudioManagerRequestData requestData(audioControlsPath, levelName, levelPreloadId); Audio::SAudioRequest request; request.nFlags = (Audio::eARF_PRIORITY_HIGH | Audio::eARF_EXECUTE_BLOCKING); request.pData = &requestData; Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequestBlocking, request); #endif // INCLUDE_AUDIO_PRODUCTION_CODE } /////////////////////////////////////////////////////////////////////////////////////////////////// IAudioProxy* CAudioSystem::GetFreeAudioProxy() { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::GetFreeAudioProxy - called from a non-Main thread!"); CAudioProxy* audioProxy = nullptr; if (!m_apAudioProxies.empty()) { audioProxy = m_apAudioProxies.back(); m_apAudioProxies.pop_back(); } else { audioProxy = azcreate(CAudioProxy, (), Audio::AudioSystemAllocator, "AudioProxyEx"); #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) if (!audioProxy) { g_audioLogger.Log(eALT_ASSERT, "AudioSystem::GetFreeAudioProxy - failed to create new AudioProxy instance!"); } #endif // INCLUDE_AUDIO_PRODUCTION_CODE } return static_cast(audioProxy); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::FreeAudioProxy(IAudioProxy* const audioProxyI) { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::FreeAudioProxy - called from a non-Main thread!"); auto const audioProxy = static_cast(audioProxyI); if (AZStd::find(m_apAudioProxiesToBeFreed.begin(), m_apAudioProxiesToBeFreed.end(), audioProxy) != m_apAudioProxiesToBeFreed.end() || AZStd::find(m_apAudioProxies.begin(), m_apAudioProxies.end(), audioProxy) != m_apAudioProxies.end()) { AZ_Warning("AudioSystem", false, "Attempting to free an already freed audio proxy"); return; } if (m_apAudioProxies.size() < g_audioCVars.m_nAudioObjectPoolSize) { m_apAudioProxies.push_back(audioProxy); } else { m_apAudioProxiesToBeFreed.push_back(audioProxy); } } /////////////////////////////////////////////////////////////////////////////////////////////////// TAudioSourceId CAudioSystem::CreateAudioSource(const SAudioInputConfig& sourceConfig) { return m_oATL.CreateAudioSource(sourceConfig); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::DestroyAudioSource(TAudioSourceId sourceId) { m_oATL.DestroyAudioSource(sourceId); } /////////////////////////////////////////////////////////////////////////////////////////////////// const char* CAudioSystem::GetAudioControlName(const EAudioControlType controlType, const TATLIDType atlID) const { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::GetAudioControlName - called from non-Main thread!"); const char* sResult = nullptr; #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) #if defined(PROVIDE_GETNAME_SUPPORT) AZStd::lock_guard lock(m_debugNameStoreMutex); switch (controlType) { case eACT_AUDIO_OBJECT: { sResult = m_debugNameStore.LookupAudioObjectName(atlID); break; } case eACT_TRIGGER: { sResult = m_debugNameStore.LookupAudioTriggerName(atlID); break; } case eACT_RTPC: { sResult = m_debugNameStore.LookupAudioRtpcName(atlID); break; } case eACT_SWITCH: { sResult = m_debugNameStore.LookupAudioSwitchName(atlID); break; } case eACT_PRELOAD: { sResult = m_debugNameStore.LookupAudioPreloadRequestName(atlID); break; } case eACT_ENVIRONMENT: { sResult = m_debugNameStore.LookupAudioEnvironmentName(atlID); break; } case eACT_SWITCH_STATE: // not handled here, use GetAudioSwitchStateName! case eACT_NONE: default: // fall-through! { g_audioLogger.Log(eALT_WARNING, "AudioSystem::GetAudioControlName - called with invalid EAudioControlType!"); break; } } #endif // PROVIDE_GETNAME_SUPPORT #endif // INCLUDE_AUDIO_PRODUCTION_CODE return sResult; } /////////////////////////////////////////////////////////////////////////////////////////////////// const char* CAudioSystem::GetAudioSwitchStateName(const TAudioControlID switchID, const TAudioSwitchStateID stateID) const { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::GetAudioSwitchStateName - called from non-Main thread!"); const char* sResult = nullptr; #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) #if defined(PROVIDE_GETNAME_SUPPORT) AZStd::lock_guard lock(m_debugNameStoreMutex); sResult = m_debugNameStore.LookupAudioSwitchStateName(switchID, stateID); #endif // PROVIDE_GETNAME_SUPPORT #endif // INCLUDE_AUDIO_PRODUCTION_CODE return sResult; } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::ExtractCompletedRequests(TAudioRequests& requestQueue, TAudioRequests& extractedCallbacks) { auto iter(requestQueue.begin()); auto iterEnd(requestQueue.end()); while (iter != iterEnd) { const CAudioRequestInternal& refRequest = (*iter); if (refRequest.IsComplete()) { // the request has completed, eligible for notification callback. // move the request to the extraction queue. extractedCallbacks.push_back(refRequest); iter = requestQueue.erase(iter); iterEnd = requestQueue.end(); continue; } ++iter; } } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::ExecuteRequestCompletionCallbacks(TAudioRequests& requestQueue, AZStd::mutex& requestQueueMutex, bool tryLock) { TAudioRequests extractedCallbacks; if (tryLock) { if (requestQueueMutex.try_lock()) { ExtractCompletedRequests(requestQueue, extractedCallbacks); requestQueueMutex.unlock(); } } else { AZStd::lock_guard lock(requestQueueMutex); ExtractCompletedRequests(requestQueue, extractedCallbacks); } // Notify listeners for (const auto& callback : extractedCallbacks) { m_oATL.NotifyListener(callback); } extractedCallbacks.clear(); } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::ProcessRequestBlocking(CAudioRequestInternal& request) { AZ_PROFILE_FUNCTION_STALL(AZ::Debug::ProfileCategory::Audio); if (m_oATL.CanProcessRequests()) { { AZStd::lock_guard lock(m_blockingRequestsMutex); m_blockingRequestsQueue.push_back(request); } m_processingEvent.release(); m_mainEvent.acquire(); ExecuteRequestCompletionCallbacks(m_blockingRequestsQueue, m_blockingRequestsMutex); } } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::ProcessRequestThreadSafe(CAudioRequestInternal request) { // Audio Thread! AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::Audio, "Thread-Safe Request: %s", request.ToString().c_str()); if (m_oATL.CanProcessRequests()) { if (request.eStatus == eARS_NONE) { request.eStatus = eARS_PENDING; m_oATL.ProcessRequest(request); } AZ_Assert(request.eStatus != eARS_PENDING, "AudioSystem::ProcessRequestThreadSafe - ATL finished processing request, but request is still in pending state!"); if (request.eStatus != eARS_PENDING) { // push the request onto a callbacks queue for main thread to process later... AZStd::lock_guard lock(m_threadSafeCallbacksMutex); m_threadSafeCallbacksQueue.push_back(request); } } } /////////////////////////////////////////////////////////////////////////////////////////////////// void CAudioSystem::ProcessRequestByPriority(CAudioRequestInternal request) { // Todo: This should handle request priority, use request priority as bus Address and process in priority order. AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::Audio, "Normal Request: %s", request.ToString().c_str()); AZ_Assert(gEnv->mMainThreadId != CryGetCurrentThreadId(), "AudioSystem::ProcessRequestByPriority - called from Main thread!"); if (m_oATL.CanProcessRequests()) { if (request.eStatus == eARS_NONE) { request.eStatus = eARS_PENDING; m_oATL.ProcessRequest(request); } AZ_Assert(request.eStatus != eARS_PENDING, "AudioSystem::ProcessRequestByPriority - ATL finished processing request, but request is still in pending state!"); if (request.eStatus != eARS_PENDING) { // push the request onto a callbacks queue for main thread to process later... AZStd::lock_guard lock(m_pendingCallbacksMutex); m_pendingCallbacksQueue.push_back(request); } } } /////////////////////////////////////////////////////////////////////////////////////////////////// bool CAudioSystem::ProcessRequests(TAudioRequests& requestQueue) { bool success = false; for (auto& request : requestQueue) { if (!(request.nInternalInfoFlags & eARIF_WAITING_FOR_REMOVAL)) { AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::Audio, "Blocking Request: %s", request.ToString().c_str()); if (request.eStatus == eARS_NONE) { request.eStatus = eARS_PENDING; m_oATL.ProcessRequest(request); success = true; } if (request.eStatus != eARS_PENDING) { if (request.nFlags & eARF_EXECUTE_BLOCKING) { request.nInternalInfoFlags |= eARIF_WAITING_FOR_REMOVAL; m_mainEvent.release(); } } else { g_audioLogger.Log(eALT_ERROR, "AudioSystem::ProcessRequests - request still in Pending state after being processed by ATL!"); } } } return success; } /////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(INCLUDE_AUDIO_PRODUCTION_CODE) void CAudioSystem::DrawAudioDebugData() { AZ_Assert(gEnv->mMainThreadId == CryGetCurrentThreadId(), "AudioSystem::DrawAudioDebugData - called from non-Main thread!"); if (g_audioCVars.m_nDrawAudioDebug > 0) { SAudioRequest oRequest; oRequest.nFlags = (eARF_PRIORITY_HIGH | eARF_EXECUTE_BLOCKING); SAudioManagerRequestData oRequestData; oRequest.pData = &oRequestData; PushRequestBlocking(oRequest); } } #endif // INCLUDE_AUDIO_PRODUCTION_CODE } // namespace Audio