微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如果我在播放声音时退出应用程序,Xaudio2 会崩溃

如何解决如果我在播放声音时退出应用程序,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 举报,一经查实,本站将立刻删除。