aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-05-31 20:55:16 -0700
committerChris Robinson <[email protected]>2023-06-01 06:31:19 -0700
commit360fdcbc721644e7b07aab7cbea4fc11bfa144d8 (patch)
treebb29ee82f156861503899015f40e95451f004013
parentf8d8a1a3900fd51dc3bffb91f88c7725982a7ccc (diff)
Handle device added/removed events with PulseAudio
-rw-r--r--alc/backends/pulseaudio.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp
index 7554b467..16a2450f 100644
--- a/alc/backends/pulseaudio.cpp
+++ b/alc/backends/pulseaudio.cpp
@@ -41,6 +41,7 @@
#include "albit.h"
#include "alc/alconfig.h"
+#include "alc/events.h"
#include "almalloc.h"
#include "alnumeric.h"
#include "alspan.h"
@@ -65,6 +66,8 @@ using uint = unsigned int;
MAGIC(pa_context_get_state); \
MAGIC(pa_context_disconnect); \
MAGIC(pa_context_set_state_callback); \
+ MAGIC(pa_context_set_subscribe_callback); \
+ MAGIC(pa_context_subscribe); \
MAGIC(pa_context_errno); \
MAGIC(pa_context_connect); \
MAGIC(pa_context_get_server_info); \
@@ -136,6 +139,8 @@ PULSE_FUNCS(MAKE_FUNC)
#define pa_context_get_state ppa_context_get_state
#define pa_context_disconnect ppa_context_disconnect
#define pa_context_set_state_callback ppa_context_set_state_callback
+#define pa_context_set_subscribe_callback ppa_context_set_subscribe_callback
+#define pa_context_subscribe ppa_context_subscribe
#define pa_context_errno ppa_context_errno
#define pa_context_connect ppa_context_connect
#define pa_context_get_server_info ppa_context_get_server_info
@@ -270,6 +275,9 @@ constexpr pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_fla
return lhs;
}
+constexpr pa_subscription_mask_t operator|(pa_subscription_mask_t lhs, pa_subscription_mask_t rhs)
+{ return pa_subscription_mask_t(lhs | al::to_underlying(rhs)); }
+
struct DevMap {
std::string name;
@@ -422,6 +430,39 @@ struct MainloopUniqueLock : public std::unique_lock<PulseMainloop> {
}
+ void setEventHandler()
+ {
+ pa_operation *op{pa_context_subscribe(mutex()->mContext,
+ PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
+ [](pa_context*, int, void *pdata) noexcept
+ { static_cast<PulseMainloop*>(pdata)->signal(); },
+ mutex())};
+ waitForOperation(op);
+
+ /* Watch for device added/removed events.
+ *
+ * TODO: Also track the "default" device, in as much as PulseAudio has
+ * the concept of a default device (whatever device is opened when not
+ * specifying a specific sink or source name). There doesn't seem to be
+ * an event for this.
+ */
+ auto handler = [](pa_context*, pa_subscription_event_type_t t, uint32_t, void*) noexcept
+ {
+ const auto eventFacility = (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK);
+ if(eventFacility == PA_SUBSCRIPTION_EVENT_SINK
+ || eventFacility == PA_SUBSCRIPTION_EVENT_SOURCE)
+ {
+ const auto eventType = (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK);
+ if(eventType == PA_SUBSCRIPTION_EVENT_NEW)
+ alc::Event(alc::EventType::DeviceAdded, "Device added");
+ else if(eventType == PA_SUBSCRIPTION_EVENT_REMOVE)
+ alc::Event(alc::EventType::DeviceRemoved, "Device removed");
+ }
+ };
+ pa_context_set_subscribe_callback(mutex()->mContext, handler, nullptr);
+ }
+
+
void contextStateCallback(pa_context *context) noexcept
{
pa_context_state_t state{pa_context_get_state(context)};
@@ -1395,6 +1436,7 @@ bool PulseBackendFactory::init()
MainloopUniqueLock plock{gGlobalMainloop};
plock.connectContext();
+ plock.setEventHandler();
return true;
}
catch(...) {