Migrated SndOut_XAudio2

This commit is contained in:
Silent 2021-07-07 21:28:21 +02:00 committed by Kojin
parent f343614640
commit bdb4ff0d83
1 changed files with 20 additions and 34 deletions

View File

@ -19,15 +19,18 @@
#include <xaudio2.h> #include <xaudio2.h>
#include <cguid.h> #include <cguid.h>
#include <atlcomcli.h>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <wil/com.h>
#include <wil/resource.h>
#include <wil/win32_helpers.h>
namespace Exception namespace Exception
{ {
class XAudio2Error : public std::runtime_error class XAudio2Error final : public std::runtime_error
{ {
private: private:
static std::string CreateErrorMessage(const HRESULT result, const std::string& msg) static std::string CreateErrorMessage(const HRESULT result, const std::string& msg)
@ -59,7 +62,7 @@ namespace Exception
static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16)); static const double SndOutNormalizer = (double)(1UL << (SndOutVolumeShift + 16));
class XAudio2Mod : public SndOutModule class XAudio2Mod final : public SndOutModule
{ {
private: private:
static const int PacketsPerBuffer = 8; static const int PacketsPerBuffer = 8;
@ -76,7 +79,7 @@ private:
const uint m_BufferSize; const uint m_BufferSize;
const uint m_BufferSizeBytes; const uint m_BufferSizeBytes;
CRITICAL_SECTION cs; wil::critical_section cs;
public: public:
int GetEmptySampleCount() int GetEmptySampleCount()
@ -86,11 +89,6 @@ private:
return state.SamplesPlayed & (m_BufferSize - 1); return state.SamplesPlayed & (m_BufferSize - 1);
} }
virtual ~BaseStreamingVoice()
{
DeleteCriticalSection(&cs);
}
BaseStreamingVoice(uint numChannels) BaseStreamingVoice(uint numChannels)
: pSourceVoice(nullptr) : pSourceVoice(nullptr)
, m_nBuffers(Config_XAudio2.NumBuffers) , m_nBuffers(Config_XAudio2.NumBuffers)
@ -98,7 +96,6 @@ private:
, 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;
@ -129,7 +126,7 @@ private:
throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: "); throw Exception::XAudio2Error(hr, "XAudio2 CreateSourceVoice failure: ");
} }
EnterCriticalSection(&cs); auto lock = cs.lock();
pSourceVoice->FlushSourceBuffers(); pSourceVoice->FlushSourceBuffers();
pSourceVoice->Start(0, 0); pSourceVoice->Start(0, 0);
@ -145,8 +142,6 @@ private:
buf.pAudioData = (BYTE*)buf.pContext; buf.pAudioData = (BYTE*)buf.pContext;
pSourceVoice->SubmitSourceBuffer(&buf); pSourceVoice->SubmitSourceBuffer(&buf);
} }
LeaveCriticalSection(&cs);
} }
STDMETHOD_(void, OnVoiceProcessingPassStart) STDMETHOD_(void, OnVoiceProcessingPassStart)
@ -190,9 +185,8 @@ private:
// blocking, and the documentation states no callbacks are called // blocking, and the documentation states no callbacks are called
// or audio data is read after it returns, so it's safe to free up // or audio data is read after it returns, so it's safe to free up
// resources. // resources.
EnterCriticalSection(&cs); auto lock = cs.lock();
m_buffer = nullptr; m_buffer = nullptr;
LeaveCriticalSection(&cs);
} }
void Init(IXAudio2* pXAudio2) void Init(IXAudio2* pXAudio2)
@ -229,14 +223,13 @@ private:
STDMETHOD_(void, OnBufferEnd) STDMETHOD_(void, OnBufferEnd)
(void* context) (void* context)
{ {
EnterCriticalSection(&cs); auto lock = cs.lock();
// All of these checks are necessary because XAudio2 is wonky shizat. // All of these checks are necessary because XAudio2 is wonky shizat.
// XXX: The pSourceVoice nullptr check seems a bit self-inflicted // XXX: The pSourceVoice nullptr check seems a bit self-inflicted
// due to the destructor logic. // due to the destructor logic.
if (pSourceVoice == nullptr || context == nullptr) if (pSourceVoice == nullptr || context == nullptr)
{ {
LeaveCriticalSection(&cs);
return; return;
} }
@ -251,30 +244,29 @@ private:
buf.pContext = context; buf.pContext = context;
pSourceVoice->SubmitSourceBuffer(&buf); pSourceVoice->SubmitSourceBuffer(&buf);
LeaveCriticalSection(&cs);
} }
}; };
HMODULE xAudio2DLL = nullptr; wil::unique_couninitialize_call xaudio2CoInitialize;
decltype(&XAudio2Create) pXAudio2Create = nullptr; wil::unique_hmodule xAudio2DLL;
CComPtr<IXAudio2> pXAudio2; wil::com_ptr_nothrow<IXAudio2> pXAudio2;
IXAudio2MasteringVoice* pMasteringVoice = nullptr; IXAudio2MasteringVoice* pMasteringVoice = nullptr;
std::unique_ptr<BaseStreamingVoice> m_voiceContext; std::unique_ptr<BaseStreamingVoice> m_voiceContext;
public: public:
s32 Init() s32 Init()
{ {
CoInitializeEx(nullptr, COINIT_MULTITHREADED); xaudio2CoInitialize = wil::CoInitializeEx_failfast(COINIT_MULTITHREADED);
try try
{ {
HRESULT hr; HRESULT hr;
xAudio2DLL = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); xAudio2DLL.reset(LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
if (xAudio2DLL == nullptr) if (xAudio2DLL == nullptr)
throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError())); throw std::runtime_error("Could not load " XAUDIO2_DLL_A ". Error code:" + std::to_string(GetLastError()));
pXAudio2Create = reinterpret_cast<decltype(&XAudio2Create)>(GetProcAddress(xAudio2DLL, "XAudio2Create")); auto pXAudio2Create = GetProcAddressByFunctionDeclaration(xAudio2DLL.get(), 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()));
@ -350,7 +342,7 @@ public:
break; break;
} }
m_voiceContext->Init(pXAudio2); m_voiceContext->Init(pXAudio2.get());
} }
catch (std::runtime_error& ex) catch (std::runtime_error& ex)
{ {
@ -380,15 +372,9 @@ public:
pMasteringVoice = nullptr; pMasteringVoice = nullptr;
pXAudio2.Release(); pXAudio2.reset();
CoUninitialize(); xAudio2DLL.reset();
xaudio2CoInitialize.reset();
if (xAudio2DLL)
{
FreeLibrary(xAudio2DLL);
xAudio2DLL = nullptr;
pXAudio2Create = nullptr;
}
} }
virtual void Configure(uptr parent) virtual void Configure(uptr parent)