I have been tying to setup xaudio2 and while I thought I succeeded, I quit the application while the sound is still playing and the program crashed. originally I made it so that when receiving a WM_CLOSE message I would make sure that the source voices had stopped. this drastically reduced the number of crashes, but still around 1/5 times I exit the application the program crashes. this is what it says "Exception thrown at 0x00007FF9974E38C7 (XAudio2_9.dll) in Game.exe: 0xC0000005: Access violation reading location 0x0000025274A680C4.". I am assuming that the xaudio2 thread is still trying to read the buffer even though I have disposed of it. I have set it up in a way so that there is a central SoundSystem class which has 2 vectors of Voices(another class), idleVoices and activeVoices. when I play a sound I grab a voice from the idle channels and play a sound, then when it is done I put it back in the idle channels and repeat.
here is the .h file
#pragma once #include <vector> #include <memory> #include <xaudio2.h> #include <algorithm> #include "Sound.h" class SoundSystem { friend class Voice; friend class Window; public: static SoundSystem& getInstance(); SoundSystem(SoundSystem&) = delete; SoundSystem& operator=(SoundSystem&) = delete; void playSound(Sound& sound, float frequency = 1.0f, float volume = 1.0f); ~SoundSystem(); private: class Voice { friend class SoundSystem; friend class Window; public: Voice() { } Voice(SoundSystem* soundSystem); void playSound(Sound& sound, float frequency = 1.0f, float volume = 1.0f); void stop(); ~Voice(); private: class VoiceCallback : public IXAudio2VoiceCallback { public: void STDMETHODCALLTYPE OnStreamEnd() override {} void STDMETHODCALLTYPE OnVoiceProcessingPassEnd() override {} void STDMETHODCALLTYPE OnVoiceProcessingPassStart(UINT32 SamplesRequired) override {} void STDMETHODCALLTYPE OnBufferEnd(void* pBufferContext) override; void STDMETHODCALLTYPE OnBufferStart(void* pBufferContext) override {} void STDMETHODCALLTYPE OnLoopEnd(void* pBufferContext) override {} void STDMETHODCALLTYPE OnVoiceError(void* pBufferContext, HRESULT Error) override {} }; IXAudio2SourceVoice* sourceVoice = nullptr; XAUDIO2_BUFFER buffer = { 0 }; }; void deactivateVoice(Voice* voice); SoundSystem(); IXAudio2* audioEngine = nullptr; IXAudio2MasteringVoice* masteringVoice = nullptr; std::vector<std::unique_ptr<Voice>> idleVoices; std::vector<std::unique_ptr<Voice>> activeVoices; const unsigned int maxVoices = 256; }; and the .cpp file
#include "SoundSystem.h" #include "..\Exception.h" SoundSystem::Voice::Voice(SoundSystem* soundSystem) { HRESULT errorCode; static VoiceCallback voiceCallback; buffer.pContext = this; if (FAILED(errorCode = soundSystem->audioEngine->CreateSourceVoice(&sourceVoice, &WaveFile::validFormat, 0, 2, &voiceCallback))) { throw Exception::AudioException("CreateSourceVoice failed", __FILE__, __LINE__, errorCode); } } void SoundSystem::Voice::playSound(Sound& sound, float frequency, float volume) { HRESULT errorCode; buffer.AudioBytes = sound.audioSize; buffer.pAudioData = sound.audioBuffer; if (FAILED(errorCode = sourceVoice->SubmitSourceBuffer(&buffer, nullptr))) { throw Exception::AudioException("SubmitSourceBuffer failed", __FILE__, __LINE__, errorCode); } if (FAILED(errorCode = sourceVoice->SetFrequencyRatio(frequency))) { throw Exception::AudioException("SetFrequencyRatio failed", __FILE__, __LINE__, errorCode); } if (FAILED(errorCode = sourceVoice->SetVolume(volume))) { throw Exception::AudioException("SetVolume failed", __FILE__, __LINE__, errorCode); } if (FAILED(errorCode = sourceVoice->Start())) { throw Exception::AudioException("Start failed", __FILE__, __LINE__, errorCode); } } void SoundSystem::Voice::stop() { sourceVoice->Stop(); sourceVoice->FlushSourceBuffers(); } SoundSystem::Voice::~Voice() { stop(); sourceVoice->DestroyVoice(); sourceVoice = nullptr; } void __stdcall SoundSystem::Voice::VoiceCallback::OnBufferEnd(void* pBufferContext) { Voice* voice = reinterpret_cast<Voice*>(pBufferContext); voice->stop(); SoundSystem::getInstance().deactivateVoice(voice); } SoundSystem& SoundSystem::getInstance() { static SoundSystem instance; return instance; } void SoundSystem::deactivateVoice(Voice* voice) { auto it = std::find_if(activeVoices.begin(), activeVoices.end(), [&](const std::unique_ptr<Voice>& v) -> bool { return voice = v.get(); }); idleVoices.push_back(std::move(*it)); activeVoices.erase(it); } SoundSystem::SoundSystem() { HRESULT errorCode; if (FAILED(errorCode = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED))) { throw Exception::AudioException("CoInitializeEx failed", __FILE__, __LINE__, errorCode); } if (FAILED(errorCode = XAudio2Create(&audioEngine, 0))) { throw Exception::AudioException("XAudio2Create failed", __FILE__, __LINE__, errorCode); } if (FAILED(errorCode = audioEngine->CreateMasteringVoice(&masteringVoice))) { throw Exception::AudioException("CreateMasteringVoice failed", __FILE__, __LINE__, errorCode); } for (int i = 0; i < maxVoices; i++) { idleVoices.push_back(std::make_unique<Voice>(this)); } } void SoundSystem::playSound(Sound& sound, float frequency, float volume) { if (idleVoices.size() > 0) { activeVoices.push_back(std::move(idleVoices.back())); idleVoices.pop_back(); activeVoices.back()->playSound(sound, frequency, volume); } } SoundSystem::~SoundSystem() { for (auto& a : idleVoices) { a.reset(); } for (auto& a : activeVoices) { a.reset(); } audioEngine->Release(); audioEngine = nullptr; masteringVoice = nullptr; CoUninitialize(); } and here is the WM_CLOSE message handling
case WM_CLOSE: for (auto& a : SoundSystem::getInstance().activeVoices) { a.get()->stop(); } ApplicationEvent applicationEvent(ApplicationEventType::WindowClose); EventSystem::getInstance().notify(&applicationEvent); PostQuitMessage(0); return 0; break; I am assuming the close message handling has something to do with it, as stopping the source voices helped, but it still crashes. any help would be appreciated.
https://stackoverflow.com/questions/66667269/xaudio2-crashes-if-i-exit-application-while-sound-is-playing March 17, 2021 at 01:05PM
没有评论:
发表评论