diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | alc/alc.cpp | 54 | ||||
-rw-r--r-- | alc/device.h | 3 | ||||
-rw-r--r-- | alc/events.cpp | 98 | ||||
-rw-r--r-- | alc/events.h | 36 | ||||
-rw-r--r-- | alc/inprogext.h | 15 |
6 files changed, 184 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bc8f2e2..e1c6db76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -813,6 +813,8 @@ set(ALC_OBJS alc/effects/pshifter.cpp alc/effects/reverb.cpp alc/effects/vmorpher.cpp + alc/events.cpp + alc/events.h alc/inprogext.h alc/panning.cpp) diff --git a/alc/alc.cpp b/alc/alc.cpp index 88aa73c5..c5d4b9d3 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -616,6 +616,9 @@ const struct { DECL(alPushDebugGroupDirectEXT), DECL(alPopDebugGroupDirectEXT), DECL(alGetDebugMessageLogDirectEXT), + + DECL(alcEventControlSOFT), + DECL(alcEventCallbackSOFT), #ifdef ALSOFT_EAX }, eaxFunctions[] = { DECL(EAXGet), @@ -1174,7 +1177,8 @@ constexpr ALCchar alcNoDeviceExtList[] = "ALC_EXT_thread_local_context " "ALC_SOFT_loopback " "ALC_SOFT_loopback_bformat " - "ALC_SOFT_reopen_device"; + "ALC_SOFT_reopen_device " + "ALC_SOFTX_system_events"; constexpr ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT " "ALC_ENUMERATION_EXT " @@ -1192,7 +1196,8 @@ constexpr ALCchar alcExtensionList[] = "ALC_SOFT_output_limiter " "ALC_SOFT_output_mode " "ALC_SOFT_pause_device " - "ALC_SOFT_reopen_device"; + "ALC_SOFT_reopen_device " + "ALC_SOFTX_system_events"; constexpr int alcMajorVersion{1}; constexpr int alcMinorVersion{1}; @@ -1815,28 +1820,6 @@ const std::array<InputRemixMap,1> X71Downmix{{ }}; -/** Stores the latest ALC device error. */ -void alcSetError(ALCdevice *device, ALCenum errorCode) -{ - WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode); - if(TrapALCError) - { -#ifdef _WIN32 - /* DebugBreak() will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - if(device) - device->LastError.store(errorCode); - else - LastNullDeviceError.store(errorCode); -} - - std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const float threshold) { static constexpr bool AutoKnee{true}; @@ -2754,6 +2737,25 @@ ContextRef GetContextRef(void) return ContextRef{context}; } +void alcSetError(ALCdevice *device, ALCenum errorCode) +{ + WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode); + if(TrapALCError) + { +#ifdef _WIN32 + /* DebugBreak() will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + if(device) + device->LastError.store(errorCode); + else + LastNullDeviceError.store(errorCode); +} /************************************************ * Standard ALC functions @@ -3436,6 +3438,8 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar alcSetError(dev.get(), ALC_INVALID_VALUE); return nullptr; } + + InitConfig(); #ifdef ALSOFT_EAX if(eax_g_is_enabled) { @@ -3463,6 +3467,8 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e alcSetError(dev.get(), ALC_INVALID_VALUE); return 0; } + + InitConfig(); #ifdef ALSOFT_EAX if(eax_g_is_enabled) { diff --git a/alc/device.h b/alc/device.h index 1274e287..c346dc9e 100644 --- a/alc/device.h +++ b/alc/device.h @@ -163,4 +163,7 @@ template<> inline std::optional<bool> ALCdevice::configValue(const char *block, const char *key) { return ConfigValueBool(DeviceName.c_str(), block, key); } +/** Stores the latest ALC device error. */ +void alcSetError(ALCdevice *device, ALCenum errorCode); + #endif diff --git a/alc/events.cpp b/alc/events.cpp new file mode 100644 index 00000000..3c9c59ee --- /dev/null +++ b/alc/events.cpp @@ -0,0 +1,98 @@ + +#include "config.h" + +#include "events.h" + +#include <optional> + +#include "alspan.h" +#include "common/threads.h" +#include "core/logging.h" +#include "device.h" + + +namespace { + +std::optional<alc::EventType> GetEventType(ALCenum type) +{ + switch(type) + { + case ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT: return alc::EventType::DefaultDeviceChanged; + case ALC_EVENT_TYPE_DEVICE_ADDED_SOFT: return alc::EventType::DeviceAdded; + case ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT: return alc::EventType::DeviceRemoved; + } + return std::nullopt; +} + +ALCenum EnumFromEventType(const alc::EventType type) +{ + switch(type) + { + case alc::EventType::DefaultDeviceChanged: return ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT; + case alc::EventType::DeviceAdded: return ALC_EVENT_TYPE_DEVICE_ADDED_SOFT; + case alc::EventType::DeviceRemoved: return ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT; + case alc::EventType::Count: break; + } + throw std::runtime_error{"Invalid EventType: "+std::to_string(al::to_underlying(type))}; +} + +} // namespace + +namespace alc { + +void Event(EventType eventType, ALCdevice *device, std::string_view message) noexcept +{ + auto eventlock = std::unique_lock{EventMutex}; + if(EventCallback && EventsEnabled.test(al::to_underlying(eventType))) + EventCallback(EnumFromEventType(eventType), device, + static_cast<ALCsizei>(message.length()), message.data(), EventUserPtr); +} + +} // namespace alc + +FORCE_ALIGN ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *types, + ALCboolean enable) noexcept +{ + if(enable != ALC_FALSE && enable != ALC_TRUE) + { + alcSetError(nullptr, ALC_INVALID_ENUM); + return ALC_FALSE; + } + if(count < 0) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return ALC_FALSE; + } + if(count == 0) + return ALC_TRUE; + if(!types) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return ALC_FALSE; + } + + std::bitset<al::to_underlying(alc::EventType::Count)> eventSet{0}; + for(ALCenum type : al::span{types, static_cast<ALCuint>(count)}) + { + auto etype = GetEventType(type); + if(!etype) + { + WARN("Invalid event type: 0x%04x\n", type); + alcSetError(nullptr, ALC_INVALID_ENUM); + return ALC_FALSE; + } + eventSet.set(al::to_underlying(*etype)); + } + + auto eventlock = std::unique_lock{alc::EventMutex}; + if(enable) alc::EventsEnabled |= eventSet; + else alc::EventsEnabled &= eventSet; + return ALC_TRUE; +} + +FORCE_ALIGN void ALC_APIENTRY alcEventCallbackSOFT(ALCEVENTPROCTYPESOFT callback, void *userParam) noexcept +{ + auto eventlock = std::unique_lock{alc::EventMutex}; + alc::EventCallback = callback; + alc::EventUserPtr = userParam; +} diff --git a/alc/events.h b/alc/events.h new file mode 100644 index 00000000..51f32e57 --- /dev/null +++ b/alc/events.h @@ -0,0 +1,36 @@ +#ifndef ALC_EVENTS_H +#define ALC_EVENTS_H + +#include "inprogext.h" +#include "opthelpers.h" + +#include <bitset> +#include <mutex> +#include <string_view> + + +namespace alc { + +enum class EventType : uint8_t { + DefaultDeviceChanged, + DeviceAdded, + DeviceRemoved, + + Count +}; + +inline std::bitset<al::to_underlying(EventType::Count)> EventsEnabled{0}; + +inline std::mutex EventMutex; + +inline ALCEVENTPROCTYPESOFT EventCallback{}; +inline void *EventUserPtr{}; + +void Event(ALCenum eventType, ALCdevice *device, std::string_view message) noexcept; + +inline void Event(ALCenum eventType, std::string_view message) noexcept +{ Event(eventType, nullptr, message); } + +} // namespace alc + +#endif /* ALC_EVENTS_H */ diff --git a/alc/inprogext.h b/alc/inprogext.h index 38ef2bf8..7cf49868 100644 --- a/alc/inprogext.h +++ b/alc/inprogext.h @@ -443,6 +443,21 @@ ALenum AL_APIENTRY EAXGetBufferModeDirect(ALCcontext *context, ALuint buffer, AL #endif #endif +#ifndef ALC_SOFT_system_events +#define ALC_SOFT_system_events +#define ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT 0x19CF +#define ALC_EVENT_TYPE_DEVICE_ADDED_SOFT 0x19D0 +#define ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT 0x19D1 +typedef void (ALC_APIENTRY*ALCEVENTPROCTYPESOFT)(ALCenum eventType, ALCdevice *device, + ALCsizei length, const ALCchar *message, void *userParam) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY*LPALCEVENTCONTROLSOFT)(ALCsizei count, const ALCenum *types, ALCboolean enable) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY*LPALCEVENTCALLBACKSOFT)(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT17; +#ifdef AL_ALEXT_PROTOTYPES +ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *types, ALCboolean enable) ALC_API_NOEXCEPT; +void ALC_APIENTRY alcEventCallbackSOFT(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT; +#endif +#endif + /* Non-standard export. Not part of any extension. */ AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) noexcept; |