From 78556ea68302b45d2d42b4dccb98ff108513d944 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 14 Apr 2026 19:15:23 +0800 Subject: [PATCH] audio: narrow render locking to snapshots --- engine/include/XCEngine/Audio/AudioMixer.h | 24 ++- engine/include/XCEngine/Audio/AudioSystem.h | 26 ++- .../Components/AudioListenerComponent.h | 45 ++++- .../Components/AudioSourceComponent.h | 92 +++++++-- engine/src/Audio/AudioMixer.cpp | 27 +-- engine/src/Audio/AudioSystem.cpp | 117 ++++++++--- .../src/Components/AudioListenerComponent.cpp | 87 ++++---- .../src/Components/AudioSourceComponent.cpp | 190 +++++++++++------- 8 files changed, 420 insertions(+), 188 deletions(-) diff --git a/engine/include/XCEngine/Audio/AudioMixer.h b/engine/include/XCEngine/Audio/AudioMixer.h index cd26e034..309f6967 100644 --- a/engine/include/XCEngine/Audio/AudioMixer.h +++ b/engine/include/XCEngine/Audio/AudioMixer.h @@ -2,9 +2,10 @@ #include #include -#include #include +#include #include +#include namespace XCEngine { namespace Audio { @@ -17,19 +18,28 @@ public: ~AudioMixer(); void SetVolume(float volume); - float GetVolume() const { return m_volume; } + float GetVolume() const { + std::lock_guard lock(m_stateMutex); + return m_volume; + } void SetMute(bool mute); - bool IsMute() const { return m_mute; } + bool IsMute() const { + std::lock_guard lock(m_stateMutex); + return m_mute; + } void AddEffect(IAudioEffect* effect); void RemoveEffect(IAudioEffect* effect); void ClearEffects(); - void ProcessAudio(float* buffer, uint32 sampleCount, uint32 channels); + void ProcessAudio(float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate = 48000); void SetOutputMixer(AudioMixer* mixer); - AudioMixer* GetOutputMixer() const { return m_outputMixer; } + AudioMixer* GetOutputMixer() const { + std::lock_guard lock(m_stateMutex); + return m_outputMixer; + } void Set3DParams(const Audio3DParams& params); const Audio3DParams& Get3DParams() const { return m_3DParams; } @@ -40,8 +50,12 @@ public: }; void SetChannelVolume(AudioChannel channel, float volume); float GetChannelVolume(AudioChannel channel) const; + [[nodiscard]] std::unique_lock AcquireStateLock() const { + return std::unique_lock(m_stateMutex); + } private: + mutable std::recursive_mutex m_stateMutex; float m_volume = 1.0f; bool m_mute = false; diff --git a/engine/include/XCEngine/Audio/AudioSystem.h b/engine/include/XCEngine/Audio/AudioSystem.h index 6819ed55..bb347f96 100644 --- a/engine/include/XCEngine/Audio/AudioSystem.h +++ b/engine/include/XCEngine/Audio/AudioSystem.h @@ -85,18 +85,40 @@ public: const Stats& GetStats() const { return m_stats; } private: + struct RenderStateSnapshot { + Math::Vector3 listenerPosition = Math::Vector3::Zero(); + Math::Quaternion listenerRotation = Math::Quaternion::Identity(); + Math::Vector3 listenerVelocity = Math::Vector3::Zero(); + AudioMixer* listenerReverbMixer = nullptr; + float listenerReverbLevel = 1.0f; + float listenerDopplerLevel = 1.0f; + float speedOfSound = 343.0f; + }; + AudioSystem(); ~AudioSystem(); AudioSystem(const AudioSystem&) = delete; AudioSystem& operator=(const AudioSystem&) = delete; - void ProcessSource(Components::AudioSourceComponent* source, float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate); - void RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sampleRate); + void CaptureRenderState(RenderStateSnapshot& snapshot); + void ProcessSource( + Components::AudioSourceComponent* source, + float* buffer, + uint32 frameCount, + uint32 channels, + uint32 sampleRate, + const RenderStateSnapshot& snapshot); + void RenderAudioBlock( + uint32 frameCount, + uint32 channels, + uint32 sampleRate, + const RenderStateSnapshot& snapshot); void DetachMixerReferences(AudioMixer* mixer); void UpdateStats(); private: + mutable std::recursive_mutex m_renderMutex; mutable std::recursive_mutex m_stateMutex; std::unique_ptr m_backend; AudioMixer m_masterMixer; diff --git a/engine/include/XCEngine/Components/AudioListenerComponent.h b/engine/include/XCEngine/Components/AudioListenerComponent.h index c644d929..382b74cb 100644 --- a/engine/include/XCEngine/Components/AudioListenerComponent.h +++ b/engine/include/XCEngine/Components/AudioListenerComponent.h @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace XCEngine { @@ -17,33 +18,60 @@ public: AudioListenerComponent(); ~AudioListenerComponent() override; - float GetEnergy() const { return m_energy; } + float GetEnergy() const { + std::lock_guard lock(m_stateMutex); + return m_energy; + } const float* GetFrequencyData() const { return m_frequencyData.data(); } size_t GetFrequencyDataSize() const { return m_frequencyData.size(); } void SetMasterVolume(float volume); - float GetMasterVolume() const { return m_masterVolume; } + float GetMasterVolume() const { + std::lock_guard lock(m_stateMutex); + return m_masterVolume; + } void SetMute(bool mute); - bool IsMute() const { return m_mute; } + bool IsMute() const { + std::lock_guard lock(m_stateMutex); + return m_mute; + } void SetDopplerLevel(float level); - float GetDopplerLevel() const { return m_dopplerLevel; } + float GetDopplerLevel() const { + std::lock_guard lock(m_stateMutex); + return m_dopplerLevel; + } void SetSpeedOfSound(float metersPerSecond); - float GetSpeedOfSound() const { return m_speedOfSound; } + float GetSpeedOfSound() const { + std::lock_guard lock(m_stateMutex); + return m_speedOfSound; + } void SetReverbLevel(float level); - float GetReverbLevel() const { return m_reverbLevel; } + float GetReverbLevel() const { + std::lock_guard lock(m_stateMutex); + return m_reverbLevel; + } void SetReverb(Audio::AudioMixer* reverb); - Audio::AudioMixer* GetReverb() const { return m_reverb; } + Audio::AudioMixer* GetReverb() const { + std::lock_guard lock(m_stateMutex); + return m_reverb; + } void Update(float deltaTime) override; + void Serialize(std::ostream& os) const override; + void Deserialize(std::istream& is) override; std::string GetName() const override { return "AudioListener"; } + [[nodiscard]] std::unique_lock AcquireStateLock() const { + return std::unique_lock(m_stateMutex); + } private: + mutable std::recursive_mutex m_stateMutex; float m_masterVolume = 1.0f; bool m_mute = false; float m_dopplerLevel = 1.0f; @@ -52,6 +80,9 @@ private: Audio::AudioMixer* m_reverb = nullptr; + Math::Vector3 m_lastPosition = Math::Vector3::Zero(); + bool m_hasLastPosition = false; + float m_energy = 0.0f; std::vector m_frequencyData; }; diff --git a/engine/include/XCEngine/Components/AudioSourceComponent.h b/engine/include/XCEngine/Components/AudioSourceComponent.h index 9f234da9..423aa81e 100644 --- a/engine/include/XCEngine/Components/AudioSourceComponent.h +++ b/engine/include/XCEngine/Components/AudioSourceComponent.h @@ -9,9 +9,10 @@ #include #include #include -#include #include +#include #include +#include namespace XCEngine { namespace Audio { @@ -28,61 +29,112 @@ public: void Play(); void Pause(); void Stop(Audio::StopMode mode = Audio::StopMode::Immediate); - bool IsPlaying() const { return m_playState == Audio::PlayState::Playing; } - bool IsPaused() const { return m_playState == Audio::PlayState::Paused; } + bool IsPlaying() const { + std::lock_guard lock(m_stateMutex); + return m_playState == Audio::PlayState::Playing; + } + bool IsPaused() const { + std::lock_guard lock(m_stateMutex); + return m_playState == Audio::PlayState::Paused; + } void SetClip(Resources::AudioClip* clip); - Resources::AudioClip* GetClip() const { return m_clip; } + Resources::AudioClip* GetClip() const { + std::lock_guard lock(m_stateMutex); + return m_clip; + } void SetClipPath(const std::string& clipPath); void ClearClip(); const std::string& GetClipPath() const { return m_clipPath; } const Resources::AssetRef& GetClipAssetRef() const { return m_clipRef; } void SetVolume(float volume); - float GetVolume() const { return m_volume; } + float GetVolume() const { + std::lock_guard lock(m_stateMutex); + return m_volume; + } void SetPitch(float pitch); - float GetPitch() const { return m_pitch; } + float GetPitch() const { + std::lock_guard lock(m_stateMutex); + return m_pitch; + } void SetPan(float pan); - float GetPan() const { return m_pan; } + float GetPan() const { + std::lock_guard lock(m_stateMutex); + return m_pan; + } void SetHRTFEnabled(bool enabled); - bool IsHRTFEnabled() const { return m_useHRTF; } + bool IsHRTFEnabled() const { + std::lock_guard lock(m_stateMutex); + return m_useHRTF; + } void SetHRTFCrossFeed(float crossFeed); - float GetHRTFCrossFeed() const { return m_hrtf.GetCrossFeed(); } + float GetHRTFCrossFeed() const { + std::lock_guard lock(m_stateMutex); + return m_hrtf.GetCrossFeed(); + } void SetHRTFQuality(Audio::uint32 level); - Audio::uint32 GetHRTFQuality() const { return m_hrtf.GetQualityLevel(); } + Audio::uint32 GetHRTFQuality() const { + std::lock_guard lock(m_stateMutex); + return m_hrtf.GetQualityLevel(); + } void SetLooping(bool loop); - bool IsLooping() const { return m_isLooping; } + bool IsLooping() const { + std::lock_guard lock(m_stateMutex); + return m_isLooping; + } void SetSpatialize(bool spatialize); - bool IsSpatialize() const { return m_spatialize; } + bool IsSpatialize() const { + std::lock_guard lock(m_stateMutex); + return m_spatialize; + } void Set3DParams(const Audio::Audio3DParams& params); const Audio::Audio3DParams& Get3DParams() const { return m_3DParams; } void SetDopplerLevel(float level); - float GetDopplerLevel() const { return m_3DParams.dopplerLevel; } + float GetDopplerLevel() const { + std::lock_guard lock(m_stateMutex); + return m_3DParams.dopplerLevel; + } void SetSpread(float spread); - float GetSpread() const { return m_3DParams.spread; } + float GetSpread() const { + std::lock_guard lock(m_stateMutex); + return m_3DParams.spread; + } void SetReverbZoneMix(float mix); - float GetReverbZoneMix() const { return m_3DParams.reverbZoneMix; } + float GetReverbZoneMix() const { + std::lock_guard lock(m_stateMutex); + return m_3DParams.reverbZoneMix; + } void SetOutputMixer(Audio::AudioMixer* mixer); - Audio::AudioMixer* GetOutputMixer() const { return m_outputMixer; } + Audio::AudioMixer* GetOutputMixer() const { + std::lock_guard lock(m_stateMutex); + return m_outputMixer; + } void SetTime(float seconds); float GetTime() const; float GetDuration() const; - float GetEnergy() const { return m_energy; } + float GetEnergy() const { + std::lock_guard lock(m_stateMutex); + return m_energy; + } void StartEnergyDetect(); void StopEnergyDetect(); - bool IsEnergyDetecting() const { return m_isEnergyDetecting; } + bool IsEnergyDetecting() const { + std::lock_guard lock(m_stateMutex); + return m_isEnergyDetecting; + } void Update(float deltaTime) override; void OnEnable() override; @@ -100,6 +152,9 @@ public: Audio::uint32 outputSampleRate = 0); std::string GetName() const override { return "AudioSource"; } + [[nodiscard]] std::unique_lock AcquireStateLock() const { + return std::unique_lock(m_stateMutex); + } private: float Compute3DAttenuation(const Math::Vector3& listenerPosition) const; @@ -112,6 +167,7 @@ private: void UpdateEnergy(const float* buffer, Audio::uint32 sampleCount); private: + mutable std::recursive_mutex m_stateMutex; Resources::ResourceHandle m_clipHandle; Resources::AudioClip* m_clip = nullptr; std::string m_clipPath; diff --git a/engine/src/Audio/AudioMixer.cpp b/engine/src/Audio/AudioMixer.cpp index 76024408..610ac528 100644 --- a/engine/src/Audio/AudioMixer.cpp +++ b/engine/src/Audio/AudioMixer.cpp @@ -9,13 +9,6 @@ namespace Audio { namespace { -std::unique_lock LockAudioState() { - if (AudioSystem* audioSystem = AudioSystem::TryGetExisting()) { - return audioSystem->AcquireStateLock(); - } - return std::unique_lock(); -} - AudioChannel ResolveChannel(uint32 channelIndex) { switch (channelIndex) { case 0: return AudioChannel::FrontLeft; @@ -49,24 +42,24 @@ AudioMixer::~AudioMixer() { } void AudioMixer::SetVolume(float volume) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_volume = std::max(0.0f, std::min(1.0f, volume)); } void AudioMixer::SetMute(bool mute) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_mute = mute; } void AudioMixer::AddEffect(IAudioEffect* effect) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); if (effect && std::find(m_effects.begin(), m_effects.end(), effect) == m_effects.end()) { m_effects.push_back(effect); } } void AudioMixer::RemoveEffect(IAudioEffect* effect) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); if (!effect) return; auto it = std::find(m_effects.begin(), m_effects.end(), effect); if (it != m_effects.end()) { @@ -75,12 +68,12 @@ void AudioMixer::RemoveEffect(IAudioEffect* effect) { } void AudioMixer::ClearEffects() { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_effects.clear(); } void AudioMixer::ProcessAudio(float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); if (!buffer || frameCount == 0 || channels == 0) { return; } @@ -115,17 +108,17 @@ void AudioMixer::ProcessAudio(float* buffer, uint32 frameCount, uint32 channels, } void AudioMixer::SetOutputMixer(AudioMixer* mixer) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_outputMixer = mixer; } void AudioMixer::Set3DParams(const Audio3DParams& params) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_3DParams = params; } void AudioMixer::SetChannelVolume(AudioChannel channel, float volume) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); auto it = m_channelVolumes.find(channel); if (it != m_channelVolumes.end()) { it->second.volume = std::max(0.0f, std::min(1.0f, volume)); @@ -133,7 +126,7 @@ void AudioMixer::SetChannelVolume(AudioChannel channel, float volume) { } float AudioMixer::GetChannelVolume(AudioChannel channel) const { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); auto it = m_channelVolumes.find(channel); if (it != m_channelVolumes.end()) { return it->second.volume; diff --git a/engine/src/Audio/AudioSystem.cpp b/engine/src/Audio/AudioSystem.cpp index 8bb92b49..1c514672 100644 --- a/engine/src/Audio/AudioSystem.cpp +++ b/engine/src/Audio/AudioSystem.cpp @@ -131,6 +131,7 @@ void AudioSystem::Initialize(const AudioConfig& config) { } void AudioSystem::Shutdown() { + std::lock_guard renderLock(m_renderMutex); std::unique_ptr backend; { std::lock_guard lock(m_stateMutex); @@ -171,25 +172,41 @@ void AudioSystem::Shutdown() { } void AudioSystem::Update(float deltaTime) { - std::lock_guard lock(m_stateMutex); - m_deltaTime = deltaTime; + IAudioBackend* backend = nullptr; + AudioConfig config{}; + bool usesPullModel = false; - if (!m_backend || !m_backend->IsRunning()) { - return; + { + std::lock_guard lock(m_stateMutex); + m_deltaTime = deltaTime; + + if (!m_backend || !m_backend->IsRunning()) { + return; + } + + backend = m_backend.get(); + usesPullModel = backend->UsesPullModel(); + if (!usesPullModel) { + config = backend->GetConfig(); + } } - if (!m_backend->UsesPullModel()) { - const auto& config = m_backend->GetConfig(); + if (!usesPullModel) { + std::lock_guard renderLock(m_renderMutex); + RenderStateSnapshot snapshot; + CaptureRenderState(snapshot); + const uint32 frameCount = config.bufferSize; - RenderAudioBlock(frameCount, config.channels, config.sampleRate); - m_backend->ProcessAudio( + RenderAudioBlock(frameCount, config.channels, config.sampleRate, snapshot); + backend->ProcessAudio( m_mixScratchBuffer.data(), frameCount, config.channels, config.sampleRate); - } else { - UpdateStats(); + return; } + + UpdateStats(); } void AudioSystem::SetBackend(std::unique_ptr backend) { @@ -278,12 +295,14 @@ void AudioSystem::SetSpeedOfSound(float metersPerSecond) { } void AudioSystem::RenderAudio(float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate) { - std::lock_guard lock(m_stateMutex); if (buffer == nullptr || frameCount == 0 || channels == 0 || sampleRate == 0) { return; } - RenderAudioBlock(frameCount, channels, sampleRate); + std::lock_guard renderLock(m_renderMutex); + RenderStateSnapshot snapshot; + CaptureRenderState(snapshot); + RenderAudioBlock(frameCount, channels, sampleRate, snapshot); const size_t sampleCount = static_cast(frameCount) * channels; std::copy_n(m_mixScratchBuffer.data(), sampleCount, buffer); } @@ -332,6 +351,7 @@ void AudioSystem::RegisterSourceComponent(Components::AudioSourceComponent* sour } void AudioSystem::UnregisterSourceComponent(Components::AudioSourceComponent* source) { + std::lock_guard renderLock(m_renderMutex); std::lock_guard lock(m_stateMutex); if (!source) { return; @@ -378,6 +398,7 @@ void AudioSystem::RegisterMixer(AudioMixer* mixer) { } void AudioSystem::UnregisterMixer(AudioMixer* mixer) { + std::lock_guard renderLock(m_renderMutex); std::lock_guard lock(m_stateMutex); if (!mixer) { return; @@ -390,6 +411,7 @@ void AudioSystem::UnregisterMixer(AudioMixer* mixer) { } void AudioSystem::UnregisterSource(Components::AudioSourceComponent* source) { + std::lock_guard renderLock(m_renderMutex); std::lock_guard lock(m_stateMutex); if (!source) { return; @@ -428,7 +450,25 @@ void AudioSystem::DetachMixerReferences(AudioMixer* mixer) { } } -void AudioSystem::ProcessSource(Components::AudioSourceComponent* source, float* buffer, uint32 frameCount, uint32 channels, uint32 sampleRate) { +void AudioSystem::CaptureRenderState(RenderStateSnapshot& snapshot) { + std::lock_guard lock(m_stateMutex); + m_activeSourceSnapshot = m_activeSources; + snapshot.listenerPosition = m_listenerPosition; + snapshot.listenerRotation = m_listenerRotation; + snapshot.listenerVelocity = m_listenerVelocity; + snapshot.listenerReverbMixer = m_listenerReverbMixer; + snapshot.listenerReverbLevel = m_listenerReverbLevel; + snapshot.listenerDopplerLevel = m_listenerDopplerLevel; + snapshot.speedOfSound = m_speedOfSound; +} + +void AudioSystem::ProcessSource( + Components::AudioSourceComponent* source, + float* buffer, + uint32 frameCount, + uint32 channels, + uint32 sampleRate, + const RenderStateSnapshot& snapshot) { if (!source || !buffer) { return; } @@ -437,15 +477,19 @@ void AudioSystem::ProcessSource(Components::AudioSourceComponent* source, float* buffer, frameCount, channels, - m_listenerPosition, - m_listenerRotation, - m_listenerVelocity, - m_listenerDopplerLevel, - m_speedOfSound, + snapshot.listenerPosition, + snapshot.listenerRotation, + snapshot.listenerVelocity, + snapshot.listenerDopplerLevel, + snapshot.speedOfSound, sampleRate); } -void AudioSystem::RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sampleRate) { +void AudioSystem::RenderAudioBlock( + uint32 frameCount, + uint32 channels, + uint32 sampleRate, + const RenderStateSnapshot& snapshot) { const size_t sampleCount = static_cast(frameCount) * channels; if (sampleCount == 0 || sampleRate == 0) { m_mixScratchBuffer.clear(); @@ -466,7 +510,6 @@ void AudioSystem::RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sa std::fill(m_sourceScratchBuffer.begin(), m_sourceScratchBuffer.end(), 0.0f); } - m_activeSourceSnapshot = m_activeSources; m_mixerScratchChildren.clear(); m_mixerScratchActiveMixers.clear(); m_mixerScratchVisiting.clear(); @@ -504,14 +547,20 @@ void AudioSystem::RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sa } }; - if (m_listenerReverbMixer != nullptr) { - registerMixerChain(m_listenerReverbMixer); + if (snapshot.listenerReverbMixer != nullptr) { + registerMixerChain(snapshot.listenerReverbMixer); } for (auto* source : m_activeSourceSnapshot) { if (source && source->IsEnabled() && source->IsPlaying()) { std::fill(m_sourceScratchBuffer.begin(), m_sourceScratchBuffer.end(), 0.0f); - ProcessSource(source, m_sourceScratchBuffer.data(), frameCount, channels, sampleRate); + ProcessSource( + source, + m_sourceScratchBuffer.data(), + frameCount, + channels, + sampleRate, + snapshot); AudioMixer* outputMixer = source->GetOutputMixer(); if (outputMixer != nullptr) { @@ -521,14 +570,14 @@ void AudioSystem::RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sa MixBufferInto(m_sourceScratchBuffer, m_mixScratchBuffer); } - if (m_listenerReverbMixer != nullptr && m_listenerReverbLevel > 0.0f) { + if (snapshot.listenerReverbMixer != nullptr && snapshot.listenerReverbLevel > 0.0f) { const float sendGain = std::clamp( - source->GetReverbZoneMix() * m_listenerReverbLevel, + source->GetReverbZoneMix() * snapshot.listenerReverbLevel, 0.0f, 1.0f); MixScaledBufferInto( m_sourceScratchBuffer, - ensureMixerBuffer(m_listenerReverbMixer), + ensureMixerBuffer(snapshot.listenerReverbMixer), sendGain); } } @@ -557,14 +606,24 @@ void AudioSystem::RenderAudioBlock(uint32 frameCount, uint32 channels, uint32 sa } void AudioSystem::UpdateStats() { + std::vector activeSources; + { + std::lock_guard lock(m_stateMutex); + activeSources = m_activeSources; + } + uint32 activeCount = 0; - for (auto* source : m_activeSources) { + for (auto* source : activeSources) { if (source && source->IsPlaying()) { activeCount++; } } - m_stats.activeSources = activeCount; - m_stats.totalSources = static_cast(m_activeSources.size()); + + { + std::lock_guard lock(m_stateMutex); + m_stats.activeSources = activeCount; + m_stats.totalSources = static_cast(activeSources.size()); + } } } // namespace Audio diff --git a/engine/src/Components/AudioListenerComponent.cpp b/engine/src/Components/AudioListenerComponent.cpp index db378d63..0a20cebe 100644 --- a/engine/src/Components/AudioListenerComponent.cpp +++ b/engine/src/Components/AudioListenerComponent.cpp @@ -7,17 +7,6 @@ namespace XCEngine { namespace Components { -namespace { - -std::unique_lock LockAudioState() { - if (Audio::AudioSystem* audioSystem = Audio::AudioSystem::TryGetExisting()) { - return audioSystem->AcquireStateLock(); - } - return std::unique_lock(); -} - -} // namespace - AudioListenerComponent::AudioListenerComponent() { Audio::AudioSystem::Get().RegisterListenerComponent(this); @@ -28,43 +17,66 @@ AudioListenerComponent::~AudioListenerComponent() { } void AudioListenerComponent::SetMasterVolume(float volume) { - auto audioStateLock = LockAudioState(); - m_masterVolume = std::max(0.0f, std::min(1.0f, volume)); - Audio::AudioSystem::Get().SetMasterVolume(m_masterVolume); + float masterVolume = 0.0f; + { + std::lock_guard lock(m_stateMutex); + m_masterVolume = std::max(0.0f, std::min(1.0f, volume)); + masterVolume = m_masterVolume; + } + Audio::AudioSystem::Get().SetMasterVolume(masterVolume); } void AudioListenerComponent::SetMute(bool mute) { - auto audioStateLock = LockAudioState(); - m_mute = mute; - Audio::AudioSystem::Get().SetMuted(m_mute); + bool isMute = false; + { + std::lock_guard lock(m_stateMutex); + m_mute = mute; + isMute = m_mute; + } + Audio::AudioSystem::Get().SetMuted(isMute); } void AudioListenerComponent::SetDopplerLevel(float level) { - auto audioStateLock = LockAudioState(); - m_dopplerLevel = std::max(0.0f, std::min(5.0f, level)); - Audio::AudioSystem::Get().SetListenerDopplerLevel(m_dopplerLevel); + float dopplerLevel = 1.0f; + { + std::lock_guard lock(m_stateMutex); + m_dopplerLevel = std::max(0.0f, std::min(5.0f, level)); + dopplerLevel = m_dopplerLevel; + } + Audio::AudioSystem::Get().SetListenerDopplerLevel(dopplerLevel); } void AudioListenerComponent::SetSpeedOfSound(float metersPerSecond) { - auto audioStateLock = LockAudioState(); - m_speedOfSound = std::max(1.0f, metersPerSecond); - Audio::AudioSystem::Get().SetSpeedOfSound(m_speedOfSound); + float speedOfSound = 343.0f; + { + std::lock_guard lock(m_stateMutex); + m_speedOfSound = std::max(1.0f, metersPerSecond); + speedOfSound = m_speedOfSound; + } + Audio::AudioSystem::Get().SetSpeedOfSound(speedOfSound); } void AudioListenerComponent::SetReverbLevel(float level) { - auto audioStateLock = LockAudioState(); - m_reverbLevel = std::max(0.0f, std::min(1.0f, level)); - Audio::AudioSystem::Get().SetListenerReverbLevel(m_reverbLevel); + float reverbLevel = 1.0f; + { + std::lock_guard lock(m_stateMutex); + m_reverbLevel = std::max(0.0f, std::min(1.0f, level)); + reverbLevel = m_reverbLevel; + } + Audio::AudioSystem::Get().SetListenerReverbLevel(reverbLevel); } void AudioListenerComponent::SetReverb(Audio::AudioMixer* reverb) { - auto audioStateLock = LockAudioState(); - m_reverb = reverb; - Audio::AudioSystem::Get().SetListenerReverbMixer(m_reverb); + Audio::AudioMixer* reverbMixer = nullptr; + { + std::lock_guard lock(m_stateMutex); + m_reverb = reverb; + reverbMixer = m_reverb; + } + Audio::AudioSystem::Get().SetListenerReverbMixer(reverbMixer); } void AudioListenerComponent::Update(float deltaTime) { - auto audioStateLock = LockAudioState(); if (!m_gameObject) { return; } @@ -73,19 +85,21 @@ void AudioListenerComponent::Update(float deltaTime) { const Math::Quaternion rotation = transform().GetRotation(); Math::Vector3 velocity = Math::Vector3::Zero(); - if (m_hasLastPosition && deltaTime > 0.0f) { - velocity = (position - m_lastPosition) / deltaTime; + { + std::lock_guard lock(m_stateMutex); + if (m_hasLastPosition && deltaTime > 0.0f) { + velocity = (position - m_lastPosition) / deltaTime; + } + m_lastPosition = position; + m_hasLastPosition = true; } Audio::AudioSystem::Get().SetListenerTransform(position, rotation); Audio::AudioSystem::Get().SetListenerVelocity(velocity); - - m_lastPosition = position; - m_hasLastPosition = true; } void AudioListenerComponent::Serialize(std::ostream& os) const { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); os << "masterVolume=" << m_masterVolume << ";"; os << "mute=" << (m_mute ? 1 : 0) << ";"; os << "dopplerLevel=" << m_dopplerLevel << ";"; @@ -94,7 +108,6 @@ void AudioListenerComponent::Serialize(std::ostream& os) const { } void AudioListenerComponent::Deserialize(std::istream& is) { - auto audioStateLock = LockAudioState(); SetMasterVolume(1.0f); SetMute(false); SetDopplerLevel(1.0f); diff --git a/engine/src/Components/AudioSourceComponent.cpp b/engine/src/Components/AudioSourceComponent.cpp index 9d655fe3..9495337c 100644 --- a/engine/src/Components/AudioSourceComponent.cpp +++ b/engine/src/Components/AudioSourceComponent.cpp @@ -144,13 +144,6 @@ void ApplyPanToBuffer(float* buffer, Audio::uint32 frameCount, Audio::uint32 cha } } -std::unique_lock LockAudioState() { - if (Audio::AudioSystem* audioSystem = Audio::AudioSystem::TryGetExisting()) { - return audioSystem->AcquireStateLock(); - } - return std::unique_lock(); -} - } // namespace AudioSourceComponent::AudioSourceComponent() { @@ -158,68 +151,96 @@ AudioSourceComponent::AudioSourceComponent() { } AudioSourceComponent::~AudioSourceComponent() { + bool wasPlaying = false; + { + std::lock_guard lock(m_stateMutex); + wasPlaying = (m_playState == Audio::PlayState::Playing); + m_playState = Audio::PlayState::Stopped; + } Audio::AudioSystem::Get().UnregisterSourceComponent(this); - if (m_playState == Audio::PlayState::Playing) { + if (wasPlaying) { Audio::AudioSystem::Get().UnregisterSource(this); } } void AudioSourceComponent::Play() { - auto audioStateLock = LockAudioState(); - if (!m_clip || !m_clip->IsValid()) { - return; + bool registerSource = false; + { + std::lock_guard lock(m_stateMutex); + if (!m_clip || !m_clip->IsValid()) { + return; + } + + if (m_playState == Audio::PlayState::Playing) { + m_samplePosition = 0; + m_playbackPosition = 0.0; + m_lastingTime = 0.0; + m_velocity = Math::Vector3::Zero(); + m_hasLastPosition = false; + m_hrtf.ResetState(); + return; + } + + if (m_playState == Audio::PlayState::Paused) { + m_playState = Audio::PlayState::Playing; + registerSource = true; + } else { + m_samplePosition = 0; + m_playbackPosition = 0.0; + m_lastingTime = 0.0; + m_velocity = Math::Vector3::Zero(); + m_hasLastPosition = false; + m_hrtf.ResetState(); + m_playState = Audio::PlayState::Playing; + registerSource = true; + } } - if (m_playState == Audio::PlayState::Playing) { - m_samplePosition = 0; - m_playbackPosition = 0.0; - m_lastingTime = 0.0; - m_velocity = Math::Vector3::Zero(); - m_hasLastPosition = false; - m_hrtf.ResetState(); - return; - } - - if (m_playState == Audio::PlayState::Paused) { - m_playState = Audio::PlayState::Playing; + if (registerSource) { Audio::AudioSystem::Get().RegisterSource(this); - return; } - - m_samplePosition = 0; - m_playbackPosition = 0.0; - m_lastingTime = 0.0; - m_velocity = Math::Vector3::Zero(); - m_hasLastPosition = false; - m_hrtf.ResetState(); - m_playState = Audio::PlayState::Playing; - Audio::AudioSystem::Get().RegisterSource(this); } void AudioSourceComponent::Pause() { - auto audioStateLock = LockAudioState(); - if (m_playState == Audio::PlayState::Playing) { - m_playState = Audio::PlayState::Paused; + bool unregisterSource = false; + { + std::lock_guard lock(m_stateMutex); + if (m_playState == Audio::PlayState::Playing) { + m_playState = Audio::PlayState::Paused; + unregisterSource = true; + } + } + + if (unregisterSource) { Audio::AudioSystem::Get().UnregisterSource(this); } } void AudioSourceComponent::Stop(Audio::StopMode mode) { - auto audioStateLock = LockAudioState(); - if (m_playState != Audio::PlayState::Stopped) { - m_playState = Audio::PlayState::Stopped; - m_samplePosition = 0; - m_playbackPosition = 0.0; - m_lastingTime = 0.0; - m_velocity = Math::Vector3::Zero(); - m_hasLastPosition = false; - m_hrtf.ResetState(); + (void)mode; + + bool unregisterSource = false; + { + std::lock_guard lock(m_stateMutex); + if (m_playState != Audio::PlayState::Stopped) { + m_playState = Audio::PlayState::Stopped; + m_samplePosition = 0; + m_playbackPosition = 0.0; + m_lastingTime = 0.0; + m_velocity = Math::Vector3::Zero(); + m_hasLastPosition = false; + m_hrtf.ResetState(); + unregisterSource = true; + } + } + + if (unregisterSource) { Audio::AudioSystem::Get().UnregisterSource(this); } } void AudioSourceComponent::SetClip(Resources::AudioClip* clip) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_clipHandle = Resources::ResourceHandle(clip); m_clip = clip; m_clipPath.clear(); @@ -246,7 +267,7 @@ void AudioSourceComponent::SetClip(Resources::AudioClip* clip) { } void AudioSourceComponent::SetClipPath(const std::string& clipPath) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_clipRef.Reset(); m_clipPath = clipPath; if (!m_clipPath.empty() && @@ -278,29 +299,29 @@ void AudioSourceComponent::SetClipPath(const std::string& clipPath) { } void AudioSourceComponent::ClearClip() { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_clipRef.Reset(); m_clipPath.clear(); SetClip(nullptr); } void AudioSourceComponent::SetVolume(float volume) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_volume = std::max(0.0f, std::min(1.0f, volume)); } void AudioSourceComponent::SetPitch(float pitch) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_pitch = std::max(0.0f, std::min(3.0f, pitch)); } void AudioSourceComponent::SetPan(float pan) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_pan = std::max(-1.0f, std::min(1.0f, pan)); } void AudioSourceComponent::SetHRTFEnabled(bool enabled) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_useHRTF = enabled; if (!enabled) { m_hrtf.ResetState(); @@ -308,27 +329,27 @@ void AudioSourceComponent::SetHRTFEnabled(bool enabled) { } void AudioSourceComponent::SetHRTFCrossFeed(float crossFeed) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_hrtf.SetCrossFeed(crossFeed); } void AudioSourceComponent::SetHRTFQuality(Audio::uint32 level) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_hrtf.SetQualityLevel(level); } void AudioSourceComponent::SetLooping(bool loop) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_isLooping = loop; } void AudioSourceComponent::SetSpatialize(bool spatialize) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_spatialize = spatialize; } void AudioSourceComponent::Set3DParams(const Audio::Audio3DParams& params) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_3DParams = params; m_3DParams.dopplerLevel = std::max(0.0f, m_3DParams.dopplerLevel); m_3DParams.speedOfSound = std::max(1.0f, m_3DParams.speedOfSound); @@ -340,27 +361,27 @@ void AudioSourceComponent::Set3DParams(const Audio::Audio3DParams& params) { } void AudioSourceComponent::SetDopplerLevel(float level) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_3DParams.dopplerLevel = std::max(0.0f, level); } void AudioSourceComponent::SetSpread(float spread) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_3DParams.spread = std::max(0.0f, std::min(1.0f, spread)); } void AudioSourceComponent::SetReverbZoneMix(float mix) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_3DParams.reverbZoneMix = std::max(0.0f, std::min(1.0f, mix)); } void AudioSourceComponent::SetOutputMixer(Audio::AudioMixer* mixer) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_outputMixer = mixer; } void AudioSourceComponent::SetTime(float seconds) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); if (!m_clip || !m_clip->IsValid()) { return; } @@ -386,10 +407,12 @@ void AudioSourceComponent::SetTime(float seconds) { } float AudioSourceComponent::GetTime() const { + std::lock_guard lock(m_stateMutex); return static_cast(m_lastingTime); } float AudioSourceComponent::GetDuration() const { + std::lock_guard lock(m_stateMutex); if (!m_clip || !m_clip->IsValid()) { return 0.0f; } @@ -397,18 +420,18 @@ float AudioSourceComponent::GetDuration() const { } void AudioSourceComponent::StartEnergyDetect() { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_isEnergyDetecting = true; m_energyHistory.clear(); } void AudioSourceComponent::StopEnergyDetect() { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); m_isEnergyDetecting = false; } void AudioSourceComponent::Update(float deltaTime) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); if (m_gameObject) { const Math::Vector3 position = transform().GetPosition(); if (m_hasLastPosition && deltaTime > 0.0f) { @@ -433,15 +456,23 @@ void AudioSourceComponent::Update(float deltaTime) { } void AudioSourceComponent::OnEnable() { - auto audioStateLock = LockAudioState(); - if (m_playState == Audio::PlayState::Playing) { + bool registerSource = false; + { + std::lock_guard lock(m_stateMutex); + registerSource = (m_playState == Audio::PlayState::Playing); + } + if (registerSource) { Audio::AudioSystem::Get().RegisterSource(this); } } void AudioSourceComponent::OnDisable() { - auto audioStateLock = LockAudioState(); - if (m_playState == Audio::PlayState::Playing) { + bool unregisterSource = false; + { + std::lock_guard lock(m_stateMutex); + unregisterSource = (m_playState == Audio::PlayState::Playing); + } + if (unregisterSource) { Audio::AudioSystem::Get().UnregisterSource(this); } } @@ -451,7 +482,7 @@ void AudioSourceComponent::OnDestroy() { } void AudioSourceComponent::Serialize(std::ostream& os) const { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); Resources::AssetRef serializedClipRef = m_clipRef; std::string serializedClipPath = m_clipPath; if (serializedClipPath.empty() && m_clip != nullptr) { @@ -491,7 +522,7 @@ void AudioSourceComponent::Serialize(std::ostream& os) const { } void AudioSourceComponent::Deserialize(std::istream& is) { - auto audioStateLock = LockAudioState(); + std::lock_guard lock(m_stateMutex); ClearClip(); SetVolume(1.0f); SetPitch(1.0f); @@ -589,7 +620,7 @@ void AudioSourceComponent::ProcessAudio(float* buffer, Audio::uint32 frameCount, float listenerDopplerLevel, float speedOfSound, Audio::uint32 outputSampleRate) { - auto audioStateLock = LockAudioState(); + std::unique_lock lock(m_stateMutex); if (m_playState != Audio::PlayState::Playing || !m_clip) { return; } @@ -654,6 +685,7 @@ void AudioSourceComponent::ProcessAudio(float* buffer, Audio::uint32 frameCount, double playbackPosition = m_playbackPosition; bool reachedClipEnd = false; Audio::uint32 renderedFrameCount = 0; + bool unregisterSource = false; for (Audio::uint32 i = 0; i < frameCount; ++i) { if (!m_isLooping && playbackPosition >= static_cast(totalFrames)) { @@ -779,13 +811,25 @@ void AudioSourceComponent::ProcessAudio(float* buffer, Audio::uint32 frameCount, m_samplePosition = static_cast(m_playbackPosition); m_lastingTime = m_playbackPosition / static_cast(clipSampleRate); } else { - Stop(); + m_playState = Audio::PlayState::Stopped; + m_samplePosition = 0; + m_playbackPosition = 0.0; + m_lastingTime = 0.0; + m_velocity = Math::Vector3::Zero(); + m_hasLastPosition = false; + m_hrtf.ResetState(); + unregisterSource = true; } } if (m_isEnergyDetecting) { UpdateEnergy(buffer, renderedFrameCount * channels); } + + lock.unlock(); + if (unregisterSource) { + Audio::AudioSystem::Get().UnregisterSource(this); + } } float AudioSourceComponent::Compute3DAttenuation(const Math::Vector3& listenerPosition) const {