mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-24 05:49:58 +00:00
Windows: Add safety checks to WASAPI code.
Seems to be crashing for some users.
This commit is contained in:
parent
b5a0af635f
commit
b3b86bc2c2
@ -46,7 +46,9 @@ public:
|
||||
|
||||
if (currentDevice_)
|
||||
CoTaskMemFree(currentDevice_);
|
||||
device->GetId(¤tDevice_);
|
||||
if (!device || FAILED(device->GetId(¤tDevice_))) {
|
||||
currentDevice_ = nullptr;
|
||||
}
|
||||
deviceChanged_ = false;
|
||||
}
|
||||
|
||||
@ -75,7 +77,7 @@ public:
|
||||
AddRef();
|
||||
*ppvInterface = (IMMNotificationClient*)this;
|
||||
} else {
|
||||
*ppvInterface = NULL;
|
||||
*ppvInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
return S_OK;
|
||||
@ -92,7 +94,11 @@ public:
|
||||
}
|
||||
|
||||
// pwstrDeviceId can be null. We consider that a new device, I think?
|
||||
if (pwstrDeviceId && !wcscmp(currentDevice_, pwstrDeviceId)) {
|
||||
bool same = currentDevice_ == pwstrDeviceId;
|
||||
if (!same && currentDevice_ && pwstrDeviceId) {
|
||||
same = !wcscmp(currentDevice_, pwstrDeviceId);
|
||||
}
|
||||
if (same) {
|
||||
// Already the current device, nothing to do.
|
||||
return S_OK;
|
||||
}
|
||||
@ -226,12 +232,14 @@ WASAPIAudioThread::~WASAPIAudioThread() {
|
||||
}
|
||||
|
||||
bool WASAPIAudioThread::ActivateDefaultDevice() {
|
||||
assert(device_ == nullptr);
|
||||
HRESULT hresult = deviceEnumerator_->GetDefaultAudioEndpoint(eRender, eMultimedia, &device_);
|
||||
if (FAILED(hresult))
|
||||
if (FAILED(hresult) || device_ == nullptr)
|
||||
return false;
|
||||
|
||||
hresult = device_->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audioInterface_);
|
||||
if (FAILED(hresult))
|
||||
assert(audioInterface_ == nullptr);
|
||||
hresult = device_->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&audioInterface_);
|
||||
if (FAILED(hresult) || audioInterface_ == nullptr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -239,15 +247,23 @@ bool WASAPIAudioThread::ActivateDefaultDevice() {
|
||||
|
||||
bool WASAPIAudioThread::InitAudioDevice() {
|
||||
REFERENCE_TIME hnsBufferDuration = REFTIMES_PER_SEC;
|
||||
assert(deviceFormat_ == nullptr);
|
||||
HRESULT hresult = audioInterface_->GetMixFormat((WAVEFORMATEX **)&deviceFormat_);
|
||||
hresult = audioInterface_->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &deviceFormat_->Format, nullptr);
|
||||
hresult = audioInterface_->GetService(IID_IAudioRenderClient, (void **)&renderClient_);
|
||||
if (FAILED(hresult))
|
||||
if (FAILED(hresult) || !deviceFormat_)
|
||||
return false;
|
||||
|
||||
hresult = audioInterface_->GetBufferSize(&numBufferFrames);
|
||||
hresult = audioInterface_->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &deviceFormat_->Format, nullptr);
|
||||
if (FAILED(hresult))
|
||||
return false;
|
||||
assert(renderClient_ == nullptr);
|
||||
hresult = audioInterface_->GetService(IID_IAudioRenderClient, (void **)&renderClient_);
|
||||
if (FAILED(hresult) || !renderClient_)
|
||||
return false;
|
||||
|
||||
numBufferFrames = 0;
|
||||
hresult = audioInterface_->GetBufferSize(&numBufferFrames);
|
||||
if (FAILED(hresult) || numBufferFrames == 0)
|
||||
return false;
|
||||
|
||||
sampleRate_ = deviceFormat_->Format.nSamplesPerSec;
|
||||
|
||||
@ -291,17 +307,23 @@ bool WASAPIAudioThread::DetectFormat() {
|
||||
return false;
|
||||
}
|
||||
|
||||
BYTE *pData;
|
||||
BYTE *pData = nullptr;
|
||||
HRESULT hresult = renderClient_->GetBuffer(numBufferFrames, &pData);
|
||||
if (FAILED(hresult) || !pData)
|
||||
return false;
|
||||
|
||||
const int numSamples = numBufferFrames * deviceFormat_->Format.nChannels;
|
||||
if (format_ == Format::IEEE_FLOAT) {
|
||||
memset(pData, 0, sizeof(float) * numSamples);
|
||||
shortBuf_ = new short[numBufferFrames * deviceFormat_->Format.nChannels];
|
||||
shortBuf_ = new short[numSamples];
|
||||
} else if (format_ == Format::PCM16) {
|
||||
memset(pData, 0, sizeof(short) * numSamples);
|
||||
}
|
||||
|
||||
hresult = renderClient_->ReleaseBuffer(numBufferFrames, 0);
|
||||
if (FAILED(hresult))
|
||||
return false;
|
||||
|
||||
actualDuration_ = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * numBufferFrames / deviceFormat_->Format.nSamplesPerSec);
|
||||
return true;
|
||||
}
|
||||
@ -309,10 +331,11 @@ bool WASAPIAudioThread::DetectFormat() {
|
||||
void WASAPIAudioThread::Run() {
|
||||
// Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756(v=vs.85).aspx
|
||||
|
||||
assert(deviceEnumerator_ == nullptr);
|
||||
HRESULT hresult = CoCreateInstance(CLSID_MMDeviceEnumerator,
|
||||
nullptr, /* Object is not created as the part of the aggregate */
|
||||
CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&deviceEnumerator_);
|
||||
if (FAILED(hresult))
|
||||
if (FAILED(hresult) || deviceEnumerator_ == nullptr)
|
||||
return;
|
||||
|
||||
if (!ActivateDefaultDevice()) {
|
||||
@ -339,12 +362,16 @@ void WASAPIAudioThread::Run() {
|
||||
}
|
||||
|
||||
hresult = audioInterface_->Start();
|
||||
if (FAILED(hresult)) {
|
||||
ERROR_LOG(SCEAUDIO, "WASAPI: Failed to start audio stream");
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD flags = 0;
|
||||
while (flags != AUDCLNT_BUFFERFLAGS_SILENT) {
|
||||
Sleep((DWORD)(actualDuration_ / REFTIMES_PER_MILLISEC / 2));
|
||||
|
||||
uint32_t pNumPaddingFrames;
|
||||
uint32_t pNumPaddingFrames = 0;
|
||||
hresult = audioInterface_->GetCurrentPadding(&pNumPaddingFrames);
|
||||
if (FAILED(hresult)) {
|
||||
// What to do?
|
||||
@ -352,9 +379,9 @@ void WASAPIAudioThread::Run() {
|
||||
}
|
||||
uint32_t pNumAvFrames = numBufferFrames - pNumPaddingFrames;
|
||||
|
||||
BYTE *pData;
|
||||
BYTE *pData = nullptr;
|
||||
hresult = renderClient_->GetBuffer(pNumAvFrames, &pData);
|
||||
if (FAILED(hresult)) {
|
||||
if (FAILED(hresult) || pData == nullptr) {
|
||||
// What to do?
|
||||
} else if (pNumAvFrames) {
|
||||
switch (format_) {
|
||||
@ -382,9 +409,11 @@ void WASAPIAudioThread::Run() {
|
||||
flags = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
}
|
||||
|
||||
hresult = renderClient_->ReleaseBuffer(pNumAvFrames, flags);
|
||||
if (FAILED(hresult)) {
|
||||
// Not much to do here either...
|
||||
if (!FAILED(hresult) && pData) {
|
||||
hresult = renderClient_->ReleaseBuffer(pNumAvFrames, flags);
|
||||
if (FAILED(hresult)) {
|
||||
// Not much to do here either...
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should use a new device.
|
||||
@ -407,6 +436,10 @@ void WASAPIAudioThread::Run() {
|
||||
}
|
||||
|
||||
hresult = audioInterface_->Start();
|
||||
if (FAILED(hresult)) {
|
||||
ERROR_LOG(SCEAUDIO, "WASAPI: Failed to start audio stream");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,6 +447,9 @@ void WASAPIAudioThread::Run() {
|
||||
Sleep((DWORD)(actualDuration_ / REFTIMES_PER_MILLISEC / 2));
|
||||
|
||||
hresult = audioInterface_->Stop();
|
||||
if (FAILED(hresult)) {
|
||||
ERROR_LOG(SCEAUDIO, "WASAPI: Failed to stop audio stream");
|
||||
}
|
||||
}
|
||||
|
||||
int WASAPIAudioBackend::RunThread() {
|
||||
|
Loading…
Reference in New Issue
Block a user