如果我在播放声音时退出应用程序,Xaudio2 会崩溃
Xaudio2 crashes if I exit application while sound is playing
我一直在尝试设置 xaudio2,虽然我以为我成功了,但我在声音仍在播放时退出了应用程序,程序崩溃了。最初我这样做是为了在收到 WM_CLOSE 消息时确保源声音已停止。这大大减少了崩溃次数,但仍然有大约 1/5 次我退出应用程序时程序崩溃。这就是它所说的“在 Game.exe 中的 0x00007FF9974E38C7 (XAudio2_9.dll) 抛出的异常:0xC0000005:访问冲突读取位置 0x0000025274A680C4。”。我假设 xaudio2 线程仍在尝试读取缓冲区,即使我已经处理了它。我以某种方式设置它,以便有一个中央 SoundSystem class,它有 2 个语音向量(另一个 class)、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 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;
};
和 .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, 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();
}
这里是 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 消息后,我仍然能够有效地播放声音,从而消除了我正在阻止它们的事实。有没有办法确保程序在那里终止?
您应该在 WM_CLOSE
中添加对 StopEngine
的调用。这将停止工作线程的所有处理并可能解决您的崩溃问题。
You may want to take a look at DirectX Tool Kit for Audio.
我一直在尝试设置 xaudio2,虽然我以为我成功了,但我在声音仍在播放时退出了应用程序,程序崩溃了。最初我这样做是为了在收到 WM_CLOSE 消息时确保源声音已停止。这大大减少了崩溃次数,但仍然有大约 1/5 次我退出应用程序时程序崩溃。这就是它所说的“在 Game.exe 中的 0x00007FF9974E38C7 (XAudio2_9.dll) 抛出的异常:0xC0000005:访问冲突读取位置 0x0000025274A680C4。”。我假设 xaudio2 线程仍在尝试读取缓冲区,即使我已经处理了它。我以某种方式设置它,以便有一个中央 SoundSystem class,它有 2 个语音向量(另一个 class)、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 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;
};
和 .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, 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();
}
这里是 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 消息后,我仍然能够有效地播放声音,从而消除了我正在阻止它们的事实。有没有办法确保程序在那里终止?
您应该在 WM_CLOSE
中添加对 StopEngine
的调用。这将停止工作线程的所有处理并可能解决您的崩溃问题。
You may want to take a look at DirectX Tool Kit for Audio.