aboutsummaryrefslogtreecommitdiffstats
path: root/alc/events.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-05-30 21:16:41 -0700
committerChris Robinson <[email protected]>2023-05-30 21:16:41 -0700
commit517bb94c0953de768f6aacca45456fd63bb2c96d (patch)
tree28852929ea0c61e1e7ad6f20233c861c5ae3f040 /alc/events.cpp
parent2e75909ce90027267775d53e997d4936d6ef31a5 (diff)
Add a callback to report system device changes
Devices being added or removed, or the default device changing. Not all backends report this (none do currently), but it'll be supported where it can.
Diffstat (limited to 'alc/events.cpp')
-rw-r--r--alc/events.cpp98
1 files changed, 98 insertions, 0 deletions
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;
+}