diff --git a/CMakeLists.txt b/CMakeLists.txt index 38625e3e9a..bfe966b5ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1791,6 +1791,10 @@ add_dependencies(${CoreLibName} GitVersion) set(WindowsFiles Windows/DSoundStream.cpp Windows/DSoundStream.h + Windows/WindowsAudio.cpp + Windows/WindowsAudio.h + Windows/WASAPIStream.cpp + Windows/WASAPIStream.h Windows/Debugger/CPURegsInterface.h Windows/Debugger/BreakpointWindow.cpp Windows/Debugger/BreakpointWindow.h diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 00bf8a3074..39c5c7b66b 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -35,7 +35,7 @@ #include #if defined(_WIN32) -#include "Windows/DSoundStream.h" +#include "Windows/WindowsAudio.h" #include "Windows/MainWindow.h" #endif diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index ca15e20856..9f763ac8a4 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -1,5 +1,5 @@ #include "Common/CommonWindows.h" -#include +#include #include #ifdef __MINGW32__ @@ -11,70 +11,14 @@ #endif #include "thread/threadutil.h" +#include "Common/Log.h" #include "Common/OSVersion.h" #include "Core/ConfigValues.h" #include "Core/Reporting.h" #include "Core/Util/AudioFormat.h" #include "Windows/W32Util/Misc.h" -#include "dsoundstream.h" - -// WASAPI begin -#include -#include -#include -#include -#include - -#pragma comment(lib, "ole32.lib") - -const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); -const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); -const IID IID_IAudioClient = __uuidof(IAudioClient); -const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); -// WASAPI end - -#define BUFSIZE 0x4000 -#define MAXWAIT 20 //ms - -class DSoundAudioBackend : public WindowsAudioBackend { -public: - DSoundAudioBackend(); - ~DSoundAudioBackend() override; - - bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object - void Update() override; - int GetSampleRate() override { return sampleRate_; } - -private: - inline int ModBufferSize(int x) { return (x + bufferSize_) % bufferSize_; } - int RunThread(); - static unsigned int WINAPI soundThread(void *param); - bool CreateBuffer(); - bool WriteDataToBuffer(DWORD offset, // Our own write cursor. - char* soundData, // Start of our data. - DWORD soundBytes); // Size of block to copy. - - CRITICAL_SECTION soundCriticalSection; - HWND window_; - HANDLE soundSyncEvent_ = NULL; - HANDLE hThread_ = NULL; - - StreamCallback callback_; - - IDirectSound8 *ds_ = NULL; - IDirectSoundBuffer *dsBuffer_ = NULL; - - int bufferSize_; // bytes - int totalRenderedBytes_; - int sampleRate_; - - volatile int threadData_; - - int currentPos_; - int lastPos_; - short realtimeBuffer_[BUFSIZE * 2]; -}; +#include "DSoundStream.h" // TODO: Get rid of this static DSoundAudioBackend *g_dsound; @@ -250,239 +194,3 @@ void DSoundAudioBackend::Update() { if (soundSyncEvent_ != NULL) SetEvent(soundSyncEvent_); } - -class WASAPIAudioBackend : public WindowsAudioBackend { -public: - WASAPIAudioBackend(); - ~WASAPIAudioBackend() override; - - bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object - void Update() override {} - int GetSampleRate() override { return sampleRate_; } - -private: - int RunThread(); - static unsigned int WINAPI soundThread(void *param); - - HANDLE hThread_; - - StreamCallback callback_; - int sampleRate_; - - volatile int threadData_; -}; - -// TODO: Make these adjustable. This is from the example in MSDN. -// 200 times/sec = 5ms, pretty good :) Wonder if all computers can handle it though. -#define REFTIMES_PER_SEC (10000000/200) -#define REFTIMES_PER_MILLISEC (REFTIMES_PER_SEC / 1000) - -WASAPIAudioBackend::WASAPIAudioBackend() : hThread_(NULL), sampleRate_(0), callback_(nullptr), threadData_(0) { -} - -WASAPIAudioBackend::~WASAPIAudioBackend() { - if (threadData_ == 0) { - threadData_ = 1; - } - - if (hThread_ != NULL) { - WaitForSingleObject(hThread_, 1000); - CloseHandle(hThread_); - hThread_ = NULL; - } - - if (threadData_ == 2) { - // blah. - } -} - -unsigned int WINAPI WASAPIAudioBackend::soundThread(void *param) { - WASAPIAudioBackend *backend = (WASAPIAudioBackend *)param; - return backend->RunThread(); -} - -bool WASAPIAudioBackend::Init(HWND window, StreamCallback callback, int sampleRate) { - threadData_ = 0; - callback_ = callback; - sampleRate_ = sampleRate; - hThread_ = (HANDLE)_beginthreadex(0, 0, soundThread, (void *)this, 0, 0); - SetThreadPriority(hThread_, THREAD_PRIORITY_ABOVE_NORMAL); - return true; -} - -int WASAPIAudioBackend::RunThread() { - // Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756(v=vs.85).aspx - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - setCurrentThreadName("WASAPI_audio"); - - IMMDeviceEnumerator *pDeviceEnumerator; - IMMDevice *pDevice; - IAudioClient *pAudioInterface; - IAudioRenderClient *pAudioRenderClient; - WAVEFORMATEXTENSIBLE *pDeviceFormat; - DWORD flags = 0; - REFERENCE_TIME hnsBufferDuration, hnsActualDuration; - UINT32 pNumBufferFrames; - UINT32 pNumPaddingFrames, pNumAvFrames; - short *shortBuf = nullptr; - int numSamples; - hnsBufferDuration = REFTIMES_PER_SEC; - - enum { - UNKNOWN_FORMAT = 0, - IEEE_FLOAT = 1, - PCM16 = 2, - } format = UNKNOWN_FORMAT; - - HRESULT hresult; - hresult = CoCreateInstance(CLSID_MMDeviceEnumerator, - NULL, /*Object is not created as the part of the aggregate */ - CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - if (FAILED(hresult)) goto bail; - - hresult = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice); - if (FAILED(hresult)) { - pDeviceEnumerator->Release(); - goto bail; - } - - hresult = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioInterface); - if (FAILED(hresult)) { - pDevice->Release(); - pDeviceEnumerator->Release(); - goto bail; - } - - hresult = pAudioInterface->GetMixFormat((WAVEFORMATEX**)&pDeviceFormat); - hresult = pAudioInterface->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &pDeviceFormat->Format, NULL); - hresult = pAudioInterface->GetService(IID_IAudioRenderClient, (void**)&pAudioRenderClient); - if (FAILED(hresult)) { - pDevice->Release(); - pDeviceEnumerator->Release(); - pAudioInterface->Release(); - goto bail; - } - hresult = pAudioInterface->GetBufferSize(&pNumBufferFrames); - if (FAILED(hresult)) { - pDevice->Release(); - pDeviceEnumerator->Release(); - pAudioInterface->Release(); - goto bail; - } - - sampleRate_ = pDeviceFormat->Format.nSamplesPerSec; - - // Don't know if PCM16 ever shows up here, the documentation only talks about float... but let's blindly - // try to support it :P - - if (pDeviceFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - if (!memcmp(&pDeviceFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(pDeviceFormat->SubFormat))) { - format = IEEE_FLOAT; - // printf("float format\n"); - } else { - ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format, expected float!"); - if (pDeviceFormat->Format.wBitsPerSample == 16 && pDeviceFormat->Format.nChannels == 2) { - format = PCM16; - } - } - } else { - ERROR_LOG_REPORT_ONCE(unexpectedformat2, SCEAUDIO, "Got unexpected non-extensible WASAPI stream format, expected extensible float!"); - if (pDeviceFormat->Format.wBitsPerSample == 16 && pDeviceFormat->Format.nChannels == 2) { - format = PCM16; - } - } - - - BYTE *pData; - hresult = pAudioRenderClient->GetBuffer(pNumBufferFrames, &pData); - numSamples = pNumBufferFrames * pDeviceFormat->Format.nChannels; - if (format == IEEE_FLOAT) { - memset(pData, 0, sizeof(float) * numSamples); - shortBuf = new short[pNumBufferFrames * pDeviceFormat->Format.nChannels]; - } else if (format == PCM16) { - memset(pData, 0, sizeof(short) * numSamples); - } - - hresult = pAudioRenderClient->ReleaseBuffer(pNumBufferFrames, flags); - hnsActualDuration = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * pNumBufferFrames / pDeviceFormat->Format.nSamplesPerSec); - - hresult = pAudioInterface->Start(); - - while (flags != AUDCLNT_BUFFERFLAGS_SILENT) { - Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2)); - - hresult = pAudioInterface->GetCurrentPadding(&pNumPaddingFrames); - if (FAILED(hresult)) { - // What to do? - pNumPaddingFrames = 0; - } - pNumAvFrames = pNumBufferFrames - pNumPaddingFrames; - - hresult = pAudioRenderClient->GetBuffer(pNumAvFrames, &pData); - if (FAILED(hresult)) { - // What to do? - } else if (pNumAvFrames) { - switch (format) { - case IEEE_FLOAT: - callback_(shortBuf, pNumAvFrames, 16, sampleRate_, 2); - if (pDeviceFormat->Format.nChannels == 2) { - ConvertS16ToF32((float *)pData, shortBuf, pNumAvFrames * pDeviceFormat->Format.nChannels); - } else { - float *ptr = (float *)pData; - int chans = pDeviceFormat->Format.nChannels; - memset(ptr, 0, pNumAvFrames * chans * sizeof(float)); - for (UINT32 i = 0; i < pNumAvFrames; i++) { - ptr[i * chans + 0] = (float)shortBuf[i * 2] * (1.0f / 32768.0f); - ptr[i * chans + 1] = (float)shortBuf[i * 2 + 1] * (1.0f / 32768.0f); - } - } - break; - case PCM16: - callback_((short *)pData, pNumAvFrames, 16, sampleRate_, 2); - break; - } - } - - if (threadData_ != 0) { - flags = AUDCLNT_BUFFERFLAGS_SILENT; - } - - hresult = pAudioRenderClient->ReleaseBuffer(pNumAvFrames, flags); - if (FAILED(hresult)) { - // Not much to do here either... - } - } - - // Wait for last data in buffer to play before stopping. - Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2)); - - delete[] shortBuf; - hresult = pAudioInterface->Stop(); - - CoTaskMemFree(pDeviceFormat); - pDeviceEnumerator->Release(); - pDevice->Release(); - pAudioInterface->Release(); - pAudioRenderClient->Release(); - -bail: - threadData_ = 2; - CoUninitialize(); - return 0; -} - -WindowsAudioBackend *CreateAudioBackend(AudioBackendType type) { - if (IsVistaOrHigher()) { - switch (type) { - case AUDIO_BACKEND_WASAPI: - case AUDIO_BACKEND_AUTO: - return new WASAPIAudioBackend(); - case AUDIO_BACKEND_DSOUND: - default: - return new DSoundAudioBackend(); - } - } else { - return new DSoundAudioBackend(); - } -} diff --git a/Windows/DSoundStream.h b/Windows/DSoundStream.h index fa101f4b71..22af665e35 100644 --- a/Windows/DSoundStream.h +++ b/Windows/DSoundStream.h @@ -1,21 +1,51 @@ #pragma once -#include "Common/CommonWindows.h" -#include "Core/Config.h" -#include "Core/ConfigValues.h" +// This should only be included from WindowsAudio.cpp and DSoundStream.cpp. -typedef int (*StreamCallback)(short *buffer, int numSamples, int bits, int rate, int channels); +#include "WindowsAudio.h" +#include +#include -// Note that the backend may override the passed in sample rate. The actual sample rate -// should be returned by GetSampleRate though. -class WindowsAudioBackend { +class DSoundAudioBackend : public WindowsAudioBackend { public: - WindowsAudioBackend() {} - virtual ~WindowsAudioBackend() {} - virtual bool Init(HWND window, StreamCallback _callback, int sampleRate) = 0; - virtual void Update() {} // Doesn't have to do anything - virtual int GetSampleRate() = 0; -}; + DSoundAudioBackend(); + ~DSoundAudioBackend() override; -// Factory -WindowsAudioBackend *CreateAudioBackend(AudioBackendType type); + bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object + void Update() override; + int GetSampleRate() override { return sampleRate_; } + +private: + inline int ModBufferSize(int x) { return (x + bufferSize_) % bufferSize_; } + int RunThread(); + static unsigned int WINAPI soundThread(void *param); + bool CreateBuffer(); + bool WriteDataToBuffer(DWORD offset, // Our own write cursor. + char* soundData, // Start of our data. + DWORD soundBytes); // Size of block to copy. + + CRITICAL_SECTION soundCriticalSection; + HWND window_; + HANDLE soundSyncEvent_ = nullptr; + HANDLE hThread_ = nullptr; + + StreamCallback callback_; + + IDirectSound8 *ds_ = nullptr; + IDirectSoundBuffer *dsBuffer_ = nullptr; + + int bufferSize_; // bytes + int totalRenderedBytes_; + int sampleRate_; + + volatile int threadData_; + + enum { + BUFSIZE = 0x4000, + MAXWAIT = 20, //ms + }; + + int currentPos_; + int lastPos_; + short realtimeBuffer_[BUFSIZE * 2]; +}; diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 0d78975928..a4efbe1117 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -398,6 +398,8 @@ + + @@ -499,6 +501,8 @@ + + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 59a100aa64..fe8fbc37a3 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -188,6 +188,12 @@ Other Platforms + + Windows\System + + + Windows\System + @@ -347,6 +353,12 @@ Other Platforms + + Windows\System + + + Windows\System + diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp new file mode 100644 index 0000000000..983d075a2f --- /dev/null +++ b/Windows/WASAPIStream.cpp @@ -0,0 +1,219 @@ +#include "WindowsAudio.h" +#include "WASAPIStream.h" +#include "Common/Log.h" +#include "Core/Reporting.h" +#include "Core/Util/AudioFormat.h" + +#include "thread/threadutil.h" + +#include +#include +#include +#include +#include + +#pragma comment(lib, "ole32.lib") + +const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); +const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); +const IID IID_IAudioClient = __uuidof(IAudioClient); +const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); + +// TODO: Make these adjustable. This is from the example in MSDN. +// 200 times/sec = 5ms, pretty good :) Wonder if all computers can handle it though. +#define REFTIMES_PER_SEC (10000000/200) +#define REFTIMES_PER_MILLISEC (REFTIMES_PER_SEC / 1000) + +WASAPIAudioBackend::WASAPIAudioBackend() : hThread_(nullptr), sampleRate_(0), callback_(nullptr), threadData_(0) { +} + +WASAPIAudioBackend::~WASAPIAudioBackend() { + if (threadData_ == 0) { + threadData_ = 1; + } + + if (hThread_) { + WaitForSingleObject(hThread_, 1000); + CloseHandle(hThread_); + hThread_ = nullptr; + } + + if (threadData_ == 2) { + // blah. + } +} + +unsigned int WINAPI WASAPIAudioBackend::soundThread(void *param) { + WASAPIAudioBackend *backend = (WASAPIAudioBackend *)param; + return backend->RunThread(); +} + +bool WASAPIAudioBackend::Init(HWND window, StreamCallback callback, int sampleRate) { + threadData_ = 0; + callback_ = callback; + sampleRate_ = sampleRate; + hThread_ = (HANDLE)_beginthreadex(0, 0, soundThread, (void *)this, 0, 0); + SetThreadPriority(hThread_, THREAD_PRIORITY_ABOVE_NORMAL); + return true; +} + +int WASAPIAudioBackend::RunThread() { + // Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756(v=vs.85).aspx + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + setCurrentThreadName("WASAPI_audio"); + + IMMDeviceEnumerator *pDeviceEnumerator; + IMMDevice *pDevice; + IAudioClient *pAudioInterface; + IAudioRenderClient *pAudioRenderClient; + WAVEFORMATEXTENSIBLE *pDeviceFormat; + DWORD flags = 0; + REFERENCE_TIME hnsBufferDuration, hnsActualDuration; + UINT32 pNumBufferFrames; + UINT32 pNumPaddingFrames, pNumAvFrames; + hnsBufferDuration = REFTIMES_PER_SEC; + + HRESULT hresult; + hresult = CoCreateInstance(CLSID_MMDeviceEnumerator, + NULL, /*Object is not created as the part of the aggregate */ + CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + if (FAILED(hresult)) goto bail; + + hresult = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice); + if (FAILED(hresult)) { + pDeviceEnumerator->Release(); + goto bail; + } + + hresult = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioInterface); + if (FAILED(hresult)) { + pDevice->Release(); + pDeviceEnumerator->Release(); + goto bail; + } + + hresult = pAudioInterface->GetMixFormat((WAVEFORMATEX**)&pDeviceFormat); + hresult = pAudioInterface->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &pDeviceFormat->Format, NULL); + hresult = pAudioInterface->GetService(IID_IAudioRenderClient, (void**)&pAudioRenderClient); + if (FAILED(hresult)) { + pDevice->Release(); + pDeviceEnumerator->Release(); + pAudioInterface->Release(); + goto bail; + } + hresult = pAudioInterface->GetBufferSize(&pNumBufferFrames); + if (FAILED(hresult)) { + pDevice->Release(); + pDeviceEnumerator->Release(); + pAudioInterface->Release(); + goto bail; + } + + sampleRate_ = pDeviceFormat->Format.nSamplesPerSec; + + enum { + UNKNOWN_FORMAT = 0, + IEEE_FLOAT = 1, + PCM16 = 2, + } format = UNKNOWN_FORMAT; + + // Don't know if PCM16 ever shows up here, the documentation only talks about float... but let's blindly + // try to support it :P + + if (pDeviceFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + if (!memcmp(&pDeviceFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(pDeviceFormat->SubFormat))) { + format = IEEE_FLOAT; + // printf("float format\n"); + } else { + ERROR_LOG_REPORT_ONCE(unexpectedformat, SCEAUDIO, "Got unexpected WASAPI 0xFFFE stream format, expected float!"); + if (pDeviceFormat->Format.wBitsPerSample == 16 && pDeviceFormat->Format.nChannels == 2) { + format = PCM16; + } + } + } else { + ERROR_LOG_REPORT_ONCE(unexpectedformat2, SCEAUDIO, "Got unexpected non-extensible WASAPI stream format, expected extensible float!"); + if (pDeviceFormat->Format.wBitsPerSample == 16 && pDeviceFormat->Format.nChannels == 2) { + format = PCM16; + } + } + + short *shortBuf = nullptr; + + BYTE *pData; + hresult = pAudioRenderClient->GetBuffer(pNumBufferFrames, &pData); + int numSamples = pNumBufferFrames * pDeviceFormat->Format.nChannels; + if (format == IEEE_FLOAT) { + memset(pData, 0, sizeof(float) * numSamples); + shortBuf = new short[pNumBufferFrames * pDeviceFormat->Format.nChannels]; + } else if (format == PCM16) { + memset(pData, 0, sizeof(short) * numSamples); + } + + hresult = pAudioRenderClient->ReleaseBuffer(pNumBufferFrames, flags); + hnsActualDuration = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * pNumBufferFrames / pDeviceFormat->Format.nSamplesPerSec); + + hresult = pAudioInterface->Start(); + + while (flags != AUDCLNT_BUFFERFLAGS_SILENT) { + Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2)); + + hresult = pAudioInterface->GetCurrentPadding(&pNumPaddingFrames); + if (FAILED(hresult)) { + // What to do? + pNumPaddingFrames = 0; + } + pNumAvFrames = pNumBufferFrames - pNumPaddingFrames; + + hresult = pAudioRenderClient->GetBuffer(pNumAvFrames, &pData); + if (FAILED(hresult)) { + // What to do? + } else if (pNumAvFrames) { + switch (format) { + case IEEE_FLOAT: + callback_(shortBuf, pNumAvFrames, 16, sampleRate_, 2); + if (pDeviceFormat->Format.nChannels == 2) { + ConvertS16ToF32((float *)pData, shortBuf, pNumAvFrames * pDeviceFormat->Format.nChannels); + } else { + float *ptr = (float *)pData; + int chans = pDeviceFormat->Format.nChannels; + memset(ptr, 0, pNumAvFrames * chans * sizeof(float)); + for (UINT32 i = 0; i < pNumAvFrames; i++) { + ptr[i * chans + 0] = (float)shortBuf[i * 2] * (1.0f / 32768.0f); + ptr[i * chans + 1] = (float)shortBuf[i * 2 + 1] * (1.0f / 32768.0f); + } + } + break; + case PCM16: + callback_((short *)pData, pNumAvFrames, 16, sampleRate_, 2); + break; + } + } + + if (threadData_ != 0) { + flags = AUDCLNT_BUFFERFLAGS_SILENT; + } + + hresult = pAudioRenderClient->ReleaseBuffer(pNumAvFrames, flags); + if (FAILED(hresult)) { + // Not much to do here either... + } + } + + // Wait for last data in buffer to play before stopping. + Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2)); + + delete[] shortBuf; + hresult = pAudioInterface->Stop(); + + CoTaskMemFree(pDeviceFormat); + pDeviceEnumerator->Release(); + pDevice->Release(); + pAudioInterface->Release(); + pAudioRenderClient->Release(); + +bail: + threadData_ = 2; + CoUninitialize(); + return 0; +} diff --git a/Windows/WASAPIStream.h b/Windows/WASAPIStream.h new file mode 100644 index 0000000000..ba0baac9ee --- /dev/null +++ b/Windows/WASAPIStream.h @@ -0,0 +1,26 @@ +#pragma once + +#include "WindowsAudio.h" + +// This should only be included from WindowsAudio.cpp and WASAPIStream.cpp. + +class WASAPIAudioBackend : public WindowsAudioBackend { +public: + WASAPIAudioBackend(); + ~WASAPIAudioBackend() override; + + bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object + void Update() override {} + int GetSampleRate() override { return sampleRate_; } + +private: + int RunThread(); + static unsigned int WINAPI soundThread(void *param); + + HANDLE hThread_; + + StreamCallback callback_; + int sampleRate_; + + volatile int threadData_; +}; \ No newline at end of file diff --git a/Windows/WindowsAudio.cpp b/Windows/WindowsAudio.cpp new file mode 100644 index 0000000000..be433b083b --- /dev/null +++ b/Windows/WindowsAudio.cpp @@ -0,0 +1,19 @@ +#include "Common/OSVersion.h" +#include "WindowsAudio.h" +#include "DSoundStream.h" +#include "WASAPIStream.h" + +WindowsAudioBackend *CreateAudioBackend(AudioBackendType type) { + if (IsVistaOrHigher()) { + switch (type) { + case AUDIO_BACKEND_WASAPI: + case AUDIO_BACKEND_AUTO: + return new WASAPIAudioBackend(); + case AUDIO_BACKEND_DSOUND: + default: + return new DSoundAudioBackend(); + } + } else { + return new DSoundAudioBackend(); + } +} diff --git a/Windows/WindowsAudio.h b/Windows/WindowsAudio.h new file mode 100644 index 0000000000..2e9d0f730e --- /dev/null +++ b/Windows/WindowsAudio.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Common/CommonWindows.h" +#include "Core/Config.h" +#include "Core/ConfigValues.h" + +typedef int(*StreamCallback)(short *buffer, int numSamples, int bits, int rate, int channels); + +// Note that the backend may override the passed in sample rate. The actual sample rate +// should be returned by GetSampleRate though. +class WindowsAudioBackend { +public: + WindowsAudioBackend() {} + virtual ~WindowsAudioBackend() {} + virtual bool Init(HWND window, StreamCallback _callback, int sampleRate) = 0; + virtual void Update() {} // Doesn't have to do anything + virtual int GetSampleRate() = 0; +}; + +// Factory +WindowsAudioBackend *CreateAudioBackend(AudioBackendType type); diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 5372d655a1..59cb44a2c0 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -47,7 +47,7 @@ #include "Core/System.h" #include "Core/Debugger/SymbolMap.h" #include "Windows/EmuThread.h" -#include "Windows/DSoundStream.h" +#include "Windows/WindowsAudio.h" #include "Windows/WindowsHost.h" #include "Windows/MainWindow.h" diff --git a/Windows/main.cpp b/Windows/main.cpp index 01c0fe6664..92e0310ea2 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -39,7 +39,7 @@ #include "Core/ConfigValues.h" #include "Core/SaveState.h" #include "Windows/EmuThread.h" -#include "Windows/DSoundStream.h" +#include "Windows/WindowsAudio.h" #include "ext/disarm.h" #include "Common/LogManager.h"