refactor(privacy): clean up the module
This commit is contained in:
140
src/util/pipewire/pipewire_backend.cpp
Normal file
140
src/util/pipewire/pipewire_backend.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "util/pipewire/pipewire_backend.hpp"
|
||||
|
||||
#include "util/pipewire/privacy_node_info.hpp"
|
||||
|
||||
namespace waybar::util::PipewireBackend {
|
||||
|
||||
static void getNodeInfo(void *data_, const struct pw_node_info *info) {
|
||||
auto *pNodeInfo = static_cast<PrivacyNodeInfo *>(data_);
|
||||
pNodeInfo->handleNodeEventInfo(info);
|
||||
|
||||
static_cast<PipewireBackend *>(pNodeInfo->data)->privacy_nodes_changed_signal_event.emit();
|
||||
}
|
||||
|
||||
static const struct pw_node_events NODE_EVENTS = {
|
||||
.version = PW_VERSION_NODE_EVENTS,
|
||||
.info = getNodeInfo,
|
||||
};
|
||||
|
||||
static void proxyDestroy(void *data) {
|
||||
static_cast<PrivacyNodeInfo *>(data)->handleProxyEventDestroy();
|
||||
}
|
||||
|
||||
static const struct pw_proxy_events PROXY_EVENTS = {
|
||||
.version = PW_VERSION_PROXY_EVENTS,
|
||||
.destroy = proxyDestroy,
|
||||
};
|
||||
|
||||
static void registryEventGlobal(void *_data, uint32_t id, uint32_t permissions, const char *type,
|
||||
uint32_t version, const struct spa_dict *props) {
|
||||
static_cast<PipewireBackend *>(_data)->handleRegistryEventGlobal(id, permissions, type, version,
|
||||
props);
|
||||
}
|
||||
|
||||
static void registryEventGlobalRemove(void *_data, uint32_t id) {
|
||||
static_cast<PipewireBackend *>(_data)->handleRegistryEventGlobalRemove(id);
|
||||
}
|
||||
|
||||
static const struct pw_registry_events REGISTRY_EVENTS = {
|
||||
.version = PW_VERSION_REGISTRY_EVENTS,
|
||||
.global = registryEventGlobal,
|
||||
.global_remove = registryEventGlobalRemove,
|
||||
};
|
||||
|
||||
PipewireBackend::PipewireBackend(PrivateConstructorTag tag)
|
||||
: mainloop_(nullptr), context_(nullptr), core_(nullptr) {
|
||||
pw_init(nullptr, nullptr);
|
||||
mainloop_ = pw_thread_loop_new("waybar", nullptr);
|
||||
if (mainloop_ == nullptr) {
|
||||
throw std::runtime_error("pw_thread_loop_new() failed.");
|
||||
}
|
||||
context_ = pw_context_new(pw_thread_loop_get_loop(mainloop_), nullptr, 0);
|
||||
if (context_ == nullptr) {
|
||||
throw std::runtime_error("pa_context_new() failed.");
|
||||
}
|
||||
core_ = pw_context_connect(context_, nullptr, 0);
|
||||
if (core_ == nullptr) {
|
||||
throw std::runtime_error("pw_context_connect() failed");
|
||||
}
|
||||
registry_ = pw_core_get_registry(core_, PW_VERSION_REGISTRY, 0);
|
||||
|
||||
spa_zero(registryListener_);
|
||||
pw_registry_add_listener(registry_, ®istryListener_, ®ISTRY_EVENTS, this);
|
||||
if (pw_thread_loop_start(mainloop_) < 0) {
|
||||
throw std::runtime_error("pw_thread_loop_start() failed.");
|
||||
}
|
||||
}
|
||||
|
||||
PipewireBackend::~PipewireBackend() {
|
||||
if (registry_ != nullptr) {
|
||||
pw_proxy_destroy((struct pw_proxy *)registry_);
|
||||
}
|
||||
|
||||
spa_zero(registryListener_);
|
||||
|
||||
if (core_ != nullptr) {
|
||||
pw_core_disconnect(core_);
|
||||
}
|
||||
|
||||
if (context_ != nullptr) {
|
||||
pw_context_destroy(context_);
|
||||
}
|
||||
|
||||
if (mainloop_ != nullptr) {
|
||||
pw_thread_loop_stop(mainloop_);
|
||||
pw_thread_loop_destroy(mainloop_);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<PipewireBackend> PipewireBackend::getInstance() {
|
||||
PrivateConstructorTag tag;
|
||||
return std::make_shared<PipewireBackend>(tag);
|
||||
}
|
||||
|
||||
void PipewireBackend::handleRegistryEventGlobal(uint32_t id, uint32_t permissions, const char *type,
|
||||
uint32_t version, const struct spa_dict *props) {
|
||||
if (props == nullptr || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) return;
|
||||
|
||||
const char *lookupStr = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
||||
if (lookupStr == nullptr) return;
|
||||
std::string mediaClass = lookupStr;
|
||||
enum PrivacyNodeType mediaType = PRIVACY_NODE_TYPE_NONE;
|
||||
if (mediaClass == "Stream/Input/Video") {
|
||||
mediaType = PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
||||
} else if (mediaClass == "Stream/Input/Audio") {
|
||||
mediaType = PRIVACY_NODE_TYPE_AUDIO_INPUT;
|
||||
} else if (mediaClass == "Stream/Output/Audio") {
|
||||
mediaType = PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *proxy = (pw_proxy *)pw_registry_bind(registry_, id, type, version, sizeof(PrivacyNodeInfo));
|
||||
|
||||
if (proxy == nullptr) return;
|
||||
|
||||
auto *pNodeInfo = (PrivacyNodeInfo *)pw_proxy_get_user_data(proxy);
|
||||
pNodeInfo->id = id;
|
||||
pNodeInfo->data = this;
|
||||
pNodeInfo->type = mediaType;
|
||||
pNodeInfo->media_class = mediaClass;
|
||||
|
||||
pw_proxy_add_listener(proxy, &pNodeInfo->proxy_listener, &PROXY_EVENTS, pNodeInfo);
|
||||
|
||||
pw_proxy_add_object_listener(proxy, &pNodeInfo->object_listener, &NODE_EVENTS, pNodeInfo);
|
||||
|
||||
privacy_nodes.insert_or_assign(id, pNodeInfo);
|
||||
}
|
||||
|
||||
void PipewireBackend::handleRegistryEventGlobalRemove(uint32_t id) {
|
||||
mutex_.lock();
|
||||
auto iter = privacy_nodes.find(id);
|
||||
if (iter != privacy_nodes.end()) {
|
||||
privacy_nodes.erase(id);
|
||||
}
|
||||
mutex_.unlock();
|
||||
|
||||
privacy_nodes_changed_signal_event.emit();
|
||||
}
|
||||
|
||||
} // namespace waybar::util::PipewireBackend
|
Reference in New Issue
Block a user