如何解决如果我在播放声音时退出应用程序,Xaudio2 会崩溃
我一直在尝试设置 xaudio2,虽然我认为我成功了,但我在声音仍在播放并且程序崩溃时退出了应用程序。最初我这样做是为了在收到 WM_CLOSE 消息时我会确保源声音已经停止。这大大减少了崩溃的次数,但仍有大约 1/5 次我退出应用程序时程序崩溃。这就是它所说的“在 Game.exe 中的 0x00007FF9974E38C7 (xaudio2_9.dll) 处抛出异常:0xC0000005:访问冲突读取位置 0x0000025274A680C4。”。我假设 xaudio2 线程仍在尝试读取缓冲区,即使我已经处理了它。我以某种方式对其进行了设置,以便有一个中央 SoundSystem 类,该类具有 2 个语音向量(另一个类)、idleVoices 和 activeVoices。当我播放一个声音时,我从空闲通道中抓取一个声音并播放一个声音,然后当它完成时我将它放回空闲通道并重复。
这里是.h文件
#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 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;
};
和 .cpp 文件
#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,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",errorCode);
}
if (Failed(errorCode = sourceVoice->SetFrequencyRatio(frequency)))
{
throw Exception::AudioException("SetFrequencyRatio Failed",errorCode);
}
if (Failed(errorCode = sourceVoice->SetVolume(volume)))
{
throw Exception::AudioException("SetVolume Failed",errorCode);
}
if (Failed(errorCode = sourceVoice->Start()))
{
throw Exception::AudioException("Start Failed",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",errorCode);
}
if (Failed(errorCode = xaudio2Create(&audioEngine,0)))
{
throw Exception::AudioException("xaudio2Create Failed",errorCode);
}
if (Failed(errorCode = audioEngine->CreateMasteringVoice(&masteringVoice)))
{
throw Exception::AudioException("CreateMasteringVoice Failed",errorCode);
}
for (int i = 0; i < maxVoices; i++)
{
idleVoices.push_back(std::make_unique<Voice>(this));
}
}
void SoundSystem::playSound(Sound& sound,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();
}
这里是 WM_CLOSE 消息处理
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;
我假设关闭消息处理与它有关,因为停止源声音有帮助,但它仍然崩溃。任何帮助将不胜感激。
编辑:我发现在收到 WM_CLOSE 消息后,我仍然可以有效地播放声音,从而消除了我正在停止它们的事实。有没有办法确保程序在那里终止?
解决方法
您应该在 StopEngine
中添加对 WM_CLOSE
的调用。这将停止工作线程的所有处理并可能解决您的崩溃问题。
您可能想看看DirectX Tool Kit for Audio。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。