spu2-x:xaudio2: Improve cleanup after an exception

Initialise pointers to nullptr, move the LoadLibrary code into the try
block (where it should have been in the first place), and use Close()
to cleanup if an exception occurs. Also initialise/destroy the critical
section in the base class constructor/destructor.

This should avoid resource leaks if an exception occurs.
This commit is contained in:
Jonathan Li 2017-04-14 09:43:10 +01:00 committed by Gregory Hainaut
parent 6c512c1973
commit 14bd5a4f59
1 changed files with 32 additions and 41 deletions

View File

@ -86,14 +86,18 @@ private:
virtual ~BaseStreamingVoice() virtual ~BaseStreamingVoice()
{ {
DeleteCriticalSection(&cs);
} }
BaseStreamingVoice(uint numChannels) BaseStreamingVoice(uint numChannels)
: m_nBuffers(Config_XAudio2.NumBuffers) : pSourceVoice(nullptr)
, qbuffer(nullptr)
, m_nBuffers(Config_XAudio2.NumBuffers)
, m_nChannels(numChannels) , m_nChannels(numChannels)
, m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer) , m_BufferSize(SndOutPacketSize * m_nChannels * PacketsPerBuffer)
, m_BufferSizeBytes(m_BufferSize * sizeof(s16)) , m_BufferSizeBytes(m_BufferSize * sizeof(s16))
{ {
InitializeCriticalSection(&cs);
} }
virtual void Init(IXAudio2 *pXAudio2) = 0; virtual void Init(IXAudio2 *pXAudio2) = 0;
@ -123,7 +127,6 @@ private:
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: "); throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: ");
} }
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
pSourceVoice->FlushSourceBuffers(); pSourceVoice->FlushSourceBuffers();
@ -173,13 +176,14 @@ private:
{ {
IXAudio2SourceVoice *killMe = pSourceVoice; IXAudio2SourceVoice *killMe = pSourceVoice;
pSourceVoice = nullptr; pSourceVoice = nullptr;
if (killMe != nullptr) {
killMe->FlushSourceBuffers(); killMe->FlushSourceBuffers();
killMe->DestroyVoice(); killMe->DestroyVoice();
}
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
safe_delete_array(qbuffer); safe_delete_array(qbuffer);
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
} }
void Init(IXAudio2 *pXAudio2) void Init(IXAudio2 *pXAudio2)
@ -238,17 +242,20 @@ private:
} }
}; };
HMODULE xAudio2DLL; HMODULE xAudio2DLL = nullptr;
#if _WIN32_WINNT >= 0x602 #if _WIN32_WINNT >= 0x602
decltype(&XAudio2Create) pXAudio2Create; decltype(&XAudio2Create) pXAudio2Create = nullptr;
#endif #endif
CComPtr<IXAudio2> pXAudio2; CComPtr<IXAudio2> pXAudio2;
IXAudio2MasteringVoice *pMasteringVoice; IXAudio2MasteringVoice *pMasteringVoice = nullptr;
BaseStreamingVoice *voiceContext; BaseStreamingVoice *voiceContext = nullptr;
public: public:
s32 Init() s32 Init()
{ {
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
try {
HRESULT hr; HRESULT hr;
#if _WIN32_WINNT >= 0x602 #if _WIN32_WINNT >= 0x602
@ -259,28 +266,16 @@ public:
pXAudio2Create = reinterpret_cast<decltype(&XAudio2Create)>(GetProcAddress(xAudio2DLL, "XAudio2Create")); pXAudio2Create = reinterpret_cast<decltype(&XAudio2Create)>(GetProcAddress(xAudio2DLL, "XAudio2Create"));
if (pXAudio2Create == nullptr) if (pXAudio2Create == nullptr)
throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError())); throw std::runtime_error("XAudio2Create not found. Error code: " + std::to_string(GetLastError()));
if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:");
#else #else
// On some systems XAudio2.7 can unload itself and cause PCSX2 to crash. // On some systems XAudio2.7 can unload itself and cause PCSX2 to crash.
// Maintain an extra library reference so it can't do so. Does not // Maintain an extra library reference so it can't do so. Does not
// affect XAudio 2.8+, but that's Win8+. See // affect XAudio 2.8+, but that's Win8+. See
// http://blogs.msdn.com/b/chuckw/archive/2015/10/09/known-issues-xaudio-2-7.aspx // http://blogs.msdn.com/b/chuckw/archive/2015/10/09/known-issues-xaudio-2-7.aspx
#ifdef _DEBUG xAudio2DLL = LoadLibrary(IsDebugBuild ? L"XAudioD2_7.dll" : L"XAudio2_7.dll");
xAudio2DLL = LoadLibrary(L"XAudioD2_7.dll"); const UINT32 flags = IsDebugBuild ? XAUDIO2_DEBUG_ENGINE : 0;
#else
xAudio2DLL = LoadLibrary(L"XAudio2_7.dll");
#endif
#endif
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
try {
#if _WIN32_WINNT >= 0x602
if (FAILED(hr = pXAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
throw Exception::XAudio2Error(hr, "Failed to init XAudio2 engine. Error Details:");
#else
UINT32 flags = 0;
if (IsDebugBuild)
flags |= XAUDIO2_DEBUG_ENGINE;
if (FAILED(hr = XAudio2Create(&pXAudio2, flags))) if (FAILED(hr = XAudio2Create(&pXAudio2, flags)))
throw Exception::XAudio2Error(hr, throw Exception::XAudio2Error(hr,
"Failed to init XAudio2 engine. XA2 may not be available on your system.\n" "Failed to init XAudio2 engine. XA2 may not be available on your system.\n"
@ -316,11 +311,8 @@ public:
speakers = 2; speakers = 2;
} }
if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate))) { if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, speakers, SampleRate)))
SysMessage("Failed creating mastering voice: %#X\n", hr); throw Exception::XAudio2Error(hr, "Failed creating mastering voice: ");
CoUninitialize();
return -1;
}
switch (speakers) { switch (speakers) {
case 2: case 2:
@ -365,8 +357,7 @@ public:
voiceContext->Init(pXAudio2); voiceContext->Init(pXAudio2);
} catch (std::runtime_error &ex) { } catch (std::runtime_error &ex) {
SysMessage(ex.what()); SysMessage(ex.what());
pXAudio2.Release(); Close();
CoUninitialize();
return -1; return -1;
} }