diff --git a/Alc/alc.cpp b/Alc/alc.cpp index fde655be..779727d1 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -161,9 +161,11 @@ BackendInfo BackendList[] = { { "qsa", QSABackendFactory::getFactory }, #endif #ifdef HAVE_DSOUND +#error no dsound >:( { "dsound", DSoundBackendFactory::getFactory }, #endif #ifdef HAVE_WINMM +#error no winmm >:( { "winmm", WinMMBackendFactory::getFactory }, #endif #ifdef HAVE_PORTAUDIO @@ -956,7 +958,7 @@ static void alc_initconfig(void) } TRACE("Supported backends: %s\n", names.c_str()); } - ReadALConfig(); + //ReadALConfig(); str = getenv("__ALSOFT_SUSPEND_CONTEXT"); if(str && *str) @@ -2692,6 +2694,20 @@ START_API_FUNC } END_API_FUNC +static void (*errorReasonCallback)(const char*) = 0; + +void alcCallErrorReasonCallback(std::string reason) +{ + if (errorReasonCallback != 0) { errorReasonCallback(reason.c_str()); } +} + +ALC_API void ALC_APIENTRY alcSetErrorReasonCallback(void (*c)(const char*)) +START_API_FUNC +{ + errorReasonCallback = c; + return; +} +END_API_FUNC /* alcSuspendContext * @@ -2705,7 +2721,9 @@ START_API_FUNC ContextRef ctx{VerifyContext(context)}; if(!ctx) + { alcSetError(nullptr, ALC_INVALID_CONTEXT); + } else ALCcontext_DeferUpdates(ctx.get()); } @@ -2723,7 +2741,9 @@ START_API_FUNC ContextRef ctx{VerifyContext(context)}; if(!ctx) + { alcSetError(nullptr, ALC_INVALID_CONTEXT); + } else ALCcontext_ProcessUpdates(ctx.get()); } @@ -2824,7 +2844,9 @@ START_API_FUNC case ALC_HRTF_SPECIFIER_SOFT: dev = VerifyDevice(Device); if(!dev) + { alcSetError(nullptr, ALC_INVALID_DEVICE); + } else { std::lock_guard _{dev->StateLock}; @@ -2858,6 +2880,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::spanFrequency = frequency; if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) { + alcCallErrorReasonCallback("alcCaptureOpenDevice failed: DecomposeDevFormat failed"); alcSetError(nullptr, ALC_INVALID_ENUM); return nullptr; } @@ -3945,6 +3971,7 @@ START_API_FUNC } catch(al::backend_exception &e) { WARN("Failed to open capture device: %s\n", e.what()); + alcCallErrorReasonCallback(std::string("alcCaptureOpenDevice failed: exception thrown (")+e.what()+")"); alcSetError(nullptr, e.errorCode()); return nullptr; } @@ -3968,11 +3995,13 @@ START_API_FUNC auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); if(iter == DeviceList.cend() || *iter != device) { + alcCallErrorReasonCallback("alcCaptureCloseDevice failed: iterator couldn't find correct device"); alcSetError(nullptr, ALC_INVALID_DEVICE); return ALC_FALSE; } if((*iter)->Type != Capture) { + alcCallErrorReasonCallback("alcCaptureCloseDevice failed: device is not capture device"); alcSetError(*iter, ALC_INVALID_DEVICE); return ALC_FALSE; } @@ -3998,19 +4027,24 @@ START_API_FUNC DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != Capture) { + alcCallErrorReasonCallback("alcCaptureStart failed: device is not capture device"); alcSetError(dev.get(), ALC_INVALID_DEVICE); return; } std::lock_guard _{dev->StateLock}; if(!dev->Connected.load(std::memory_order_acquire)) + { + alcCallErrorReasonCallback("alcCaptureStart failed: device could not be loaded"); alcSetError(dev.get(), ALC_INVALID_DEVICE); + } else if(!dev->Flags.get()) { if(dev->Backend->start()) dev->Flags.set(); else { + alcCallErrorReasonCallback("alcCaptureStart failed: backend start failed"); aluHandleDisconnect(dev.get(), "Device start failure"); alcSetError(dev.get(), ALC_INVALID_DEVICE); } @@ -4023,7 +4057,10 @@ START_API_FUNC { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != Capture) + { + alcCallErrorReasonCallback("alcCaptureStop failed: device is not capture device"); alcSetError(dev.get(), ALC_INVALID_DEVICE); + } else { std::lock_guard _{dev->StateLock}; @@ -4040,6 +4077,7 @@ START_API_FUNC DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != Capture) { + alcCallErrorReasonCallback("alcCaptureSamples failed: device is not capture device"); alcSetError(dev.get(), ALC_INVALID_DEVICE); return; } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 84e85fe6..33d6a74f 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,13 @@ #include "compat.h" #include "converter.h" +extern void alcCallErrorReasonCallback(std::string reason); + +static std::string toStringHex(unsigned long i) { + std::stringstream stream; + stream << "0x" << std::hex << i; + return stream.str(); +} /* Some headers seem to define these as macros for __uuidof, which is annoying * since some headers don't declare them at all. Hopefully the ifdef is enough @@ -695,6 +703,7 @@ ALCenum WasapiPlayback::open(const ALCchar *name) mDevId.clear(); + alcCallErrorReasonCallback("WASAPI playback device init failed: HRESULT "+toStringHex(hr)); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } @@ -1222,7 +1231,9 @@ ALCenum WasapiCapture::open(const ALCchar *name) mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); if(mNotifyEvent == nullptr) { - ERR("Failed to create notify event: %lu\n", GetLastError()); + DWORD error = GetLastError(); + ERR("Failed to create notify event: %lu\n", error); + alcCallErrorReasonCallback(std::string("WASAPI capture open failed: failed to create notify event (")+toStringHex(error)+")"); hr = E_FAIL; } @@ -1268,6 +1279,7 @@ ALCenum WasapiCapture::open(const ALCchar *name) mDevId.clear(); + alcCallErrorReasonCallback(std::string("WASAPI capture open failed: HRESULT ")+toStringHex(hr)+" (1)"); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } @@ -1275,6 +1287,7 @@ ALCenum WasapiCapture::open(const ALCchar *name) hr = pushMessage(MsgType::ResetDevice).get(); if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture open failed: HRESULT ")+toStringHex(hr)+" (2)"); if(hr == E_OUTOFMEMORY) return ALC_OUT_OF_MEMORY; return ALC_INVALID_VALUE; @@ -1308,6 +1321,7 @@ HRESULT WasapiCapture::openProxy() if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy open failed: HRESULT ")+toStringHex(hr)); if(mMMDev) mMMDev->Release(); mMMDev = nullptr; @@ -1337,6 +1351,7 @@ HRESULT WasapiCapture::resetProxy() HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy reset failed: failed to reactivate audio client (HRESULT ")+toStringHex(hr)+")"); ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } @@ -1418,6 +1433,7 @@ HRESULT WasapiCapture::resetProxy() hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy reset failed: failed to check format support (HRESULT ")+toStringHex(hr)+")"); ERR("Failed to check format support: 0x%08lx\n", hr); return hr; } @@ -1525,6 +1541,7 @@ HRESULT WasapiCapture::resetProxy() 0, &OutputType.Format, nullptr); if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy reset failed: failed to initialize audio client (HRESULT ")+toStringHex(hr)+")"); ERR("Failed to initialize audio client: 0x%08lx\n", hr); return hr; } @@ -1536,6 +1553,7 @@ HRESULT WasapiCapture::resetProxy() hr = mClient->GetBufferSize(&buffer_len); if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy reset failed: failed to get buffer size (HRESULT ")+toStringHex(hr)+")"); ERR("Failed to get buffer size: 0x%08lx\n", hr); return hr; } @@ -1547,6 +1565,7 @@ HRESULT WasapiCapture::resetProxy() mRing = CreateRingBuffer(buffer_len, mDevice->frameSizeFromFmt(), false); if(!mRing) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy reset failed: failed to allocate capture ring buffer")); ERR("Failed to allocate capture ring buffer\n"); return E_OUTOFMEMORY; } @@ -1554,6 +1573,7 @@ HRESULT WasapiCapture::resetProxy() hr = mClient->SetEventHandle(mNotifyEvent); if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture proxy reset failed: failed to set event handle (HRESULT ")+toStringHex(hr)+")"); ERR("Failed to set event handle: 0x%08lx\n", hr); return hr; } @@ -1565,6 +1585,10 @@ HRESULT WasapiCapture::resetProxy() ALCboolean WasapiCapture::start() { HRESULT hr{pushMessage(MsgType::StartDevice).get()}; + if (FAILED(hr)) + { + alcCallErrorReasonCallback(std::string("WASAPI capture start failed: HRESULT ")+toStringHex(hr)); + } return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } @@ -1575,6 +1599,7 @@ HRESULT WasapiCapture::startProxy() HRESULT hr{mClient->Start()}; if(FAILED(hr)) { + alcCallErrorReasonCallback(std::string("WASAPI capture start failed: failed to start audio client (HRESULT ")+toStringHex(hr)+")"); ERR("Failed to start audio client: 0x%08lx\n", hr); return hr; } @@ -1588,9 +1613,17 @@ HRESULT WasapiCapture::startProxy() mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; } + catch(std::exception& e) { + mCapture->Release(); + mCapture = nullptr; + alcCallErrorReasonCallback(std::string("WASAPI capture start failed: failed to start thread (")+e.what()+")"); + ERR("Failed to start thread\n"); + hr = E_FAIL; + } catch(...) { mCapture->Release(); mCapture = nullptr; + alcCallErrorReasonCallback(std::string("WASAPI capture start failed: failed to start thread (unknown exception type)")); ERR("Failed to start thread\n"); hr = E_FAIL; } @@ -1649,6 +1682,12 @@ bool WasapiBackendFactory::init() InitResult = future.get(); } catch(...) { + //TODO: log this? + } + + if (FAILED(InitResult)) + { + alcCallErrorReasonCallback(std::string("WASAPI backend factory init failed: HRESULT ")+toStringHex(InitResult)); } return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index ee0bb2dc..2b17acce 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -125,7 +125,6 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "compat.h" #include "threads.h" - #if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64)) using reg_type = unsigned int; @@ -482,6 +481,7 @@ void *GetSymbol(void *handle, const char *name) return ret; } +extern void alcCallErrorReasonCallback(std::string reason); void al_print(FILE *logfile, const char *fmt, ...) { @@ -502,6 +502,8 @@ void al_print(FILE *logfile, const char *fmt, ...) va_end(args2); va_end(args); + alcCallErrorReasonCallback(str); + std::wstring wstr{utf8_to_wstr(str)}; fprintf(logfile, "%ls", wstr.c_str()); fflush(logfile); diff --git a/include/AL/alc.h b/include/AL/alc.h index 5786bad2..d308fbeb 100644 --- a/include/AL/alc.h +++ b/include/AL/alc.h @@ -187,6 +187,8 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device); */ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); +ALC_API void ALC_APIENTRY alcSetErrorReasonCallback(void (*c)(const char*)); + /** * Extension support. *