aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--alc/alc.cpp54
-rw-r--r--alc/device.h3
-rw-r--r--alc/events.cpp98
-rw-r--r--alc/events.h36
-rw-r--r--alc/inprogext.h15
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;