Add the PrivacyNodeInfo object as pw_proxy data

This commit is contained in:
Erik Reider 2023-10-31 11:37:28 +01:00
parent c60a8e9836
commit 49caa4bf31
4 changed files with 40 additions and 56 deletions

View File

@ -30,7 +30,7 @@ class PipewireBackend {
sigc::signal<void> privacy_nodes_changed_signal_event; sigc::signal<void> privacy_nodes_changed_signal_event;
std::unordered_map<uint32_t, PrivacyNodeInfo> privacy_nodes; std::unordered_map<uint32_t, PrivacyNodeInfo*> privacy_nodes;
static std::shared_ptr<PipewireBackend> getInstance(); static std::shared_ptr<PipewireBackend> getInstance();

View File

@ -32,17 +32,8 @@ class PrivacyNodeInfo {
struct spa_hook object_listener; struct spa_hook object_listener;
struct spa_hook proxy_listener; struct spa_hook proxy_listener;
bool changed = false;
void *data; void *data;
PrivacyNodeInfo(uint32_t id_, void *data_) : id(id_), data(data_) {}
~PrivacyNodeInfo() {
spa_hook_remove(&object_listener);
spa_hook_remove(&proxy_listener);
}
std::string get_name() { std::string get_name() {
const std::vector<std::string *> names{&application_name, &node_name}; const std::vector<std::string *> names{&application_name, &node_name};
std::string name = "Unknown Application"; std::string name = "Unknown Application";
@ -59,7 +50,7 @@ class PrivacyNodeInfo {
std::string get_icon_name() { std::string get_icon_name() {
const std::vector<std::string *> names{&application_icon_name, &pipewire_access_portal_app_id, const std::vector<std::string *> names{&application_icon_name, &pipewire_access_portal_app_id,
&application_name, &node_name}; &application_name, &node_name};
std::string name = "application-x-executable-symbolic"; const std::string name = "application-x-executable-symbolic";
for (auto &name_ : names) { for (auto &name_ : names) {
if (name_ != nullptr && name_->length() > 0 && DefaultGtkIconThemeWrapper::has_icon(*name_)) { if (name_ != nullptr && name_->length() > 0 && DefaultGtkIconThemeWrapper::has_icon(*name_)) {
return *name_; return *name_;

View File

@ -78,17 +78,17 @@ void Privacy::onPrivacyNodesChanged() {
nodes_screenshare.clear(); nodes_screenshare.clear();
for (auto& node : backend->privacy_nodes) { for (auto& node : backend->privacy_nodes) {
switch (node.second.state) { switch (node.second->state) {
case PW_NODE_STATE_RUNNING: case PW_NODE_STATE_RUNNING:
switch (node.second.type) { switch (node.second->type) {
case PRIVACY_NODE_TYPE_VIDEO_INPUT: case PRIVACY_NODE_TYPE_VIDEO_INPUT:
nodes_screenshare.push_back(&node.second); nodes_screenshare.push_back(node.second);
break; break;
case PRIVACY_NODE_TYPE_AUDIO_INPUT: case PRIVACY_NODE_TYPE_AUDIO_INPUT:
nodes_audio_in.push_back(&node.second); nodes_audio_in.push_back(node.second);
break; break;
case PRIVACY_NODE_TYPE_AUDIO_OUTPUT: case PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
nodes_audio_out.push_back(&node.second); nodes_audio_out.push_back(node.second);
break; break;
case PRIVACY_NODE_TYPE_NONE: case PRIVACY_NODE_TYPE_NONE:
continue; continue;

View File

@ -4,7 +4,6 @@
namespace waybar::util::PipewireBackend { namespace waybar::util::PipewireBackend {
// TODO: Refresh on suspend wake
static void get_node_info(void *data_, const struct pw_node_info *info) { static void get_node_info(void *data_, const struct pw_node_info *info) {
PrivacyNodeInfo *p_node_info = static_cast<PrivacyNodeInfo *>(data_); PrivacyNodeInfo *p_node_info = static_cast<PrivacyNodeInfo *>(data_);
PipewireBackend *backend = (PipewireBackend *)p_node_info->data; PipewireBackend *backend = (PipewireBackend *)p_node_info->data;
@ -15,15 +14,6 @@ static void get_node_info(void *data_, const struct pw_node_info *info) {
spa_dict_for_each(item, info->props) { spa_dict_for_each(item, info->props) {
if (strcmp(item->key, PW_KEY_CLIENT_ID) == 0) { if (strcmp(item->key, PW_KEY_CLIENT_ID) == 0) {
p_node_info->client_id = strtoul(item->value, NULL, 10); p_node_info->client_id = strtoul(item->value, NULL, 10);
} else if (strcmp(item->key, PW_KEY_MEDIA_CLASS) == 0) {
p_node_info->media_class = item->value;
if (strcmp(p_node_info->media_class.c_str(), "Stream/Input/Video") == 0) {
p_node_info->type = PRIVACY_NODE_TYPE_VIDEO_INPUT;
} else if (strcmp(p_node_info->media_class.c_str(), "Stream/Input/Audio") == 0) {
p_node_info->type = PRIVACY_NODE_TYPE_AUDIO_INPUT;
} else if (strcmp(p_node_info->media_class.c_str(), "Stream/Output/Audio") == 0) {
p_node_info->type = PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
}
} else if (strcmp(item->key, PW_KEY_MEDIA_NAME) == 0) { } else if (strcmp(item->key, PW_KEY_MEDIA_NAME) == 0) {
p_node_info->media_name = item->value; p_node_info->media_name = item->value;
} else if (strcmp(item->key, PW_KEY_NODE_NAME) == 0) { } else if (strcmp(item->key, PW_KEY_NODE_NAME) == 0) {
@ -37,22 +27,7 @@ static void get_node_info(void *data_, const struct pw_node_info *info) {
} }
} }
if (p_node_info->type != PRIVACY_NODE_TYPE_NONE) {
backend->mutex_.lock();
p_node_info->changed = true;
backend->privacy_nodes.insert_or_assign(info->id, *p_node_info);
backend->mutex_.unlock();
backend->privacy_nodes_changed_signal_event.emit(); backend->privacy_nodes_changed_signal_event.emit();
} else {
if (p_node_info->changed) {
backend->mutex_.lock();
backend->privacy_nodes.erase(info->id);
backend->mutex_.unlock();
backend->privacy_nodes_changed_signal_event.emit();
}
}
} }
static const struct pw_node_events node_events = { static const struct pw_node_events node_events = {
@ -76,27 +51,45 @@ static void registry_event_global(void *_data, uint32_t id, uint32_t permissions
uint32_t version, const struct spa_dict *props) { uint32_t version, const struct spa_dict *props) {
if (!props || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) return; if (!props || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) return;
PipewireBackend *backend = static_cast<PipewireBackend *>(_data); const char *lookup_str = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
struct pw_proxy *proxy = (pw_proxy *)pw_registry_bind(backend->registry, id, type, version, 0); if (!lookup_str) return;
if (proxy) { std::string media_class = lookup_str;
PrivacyNodeInfo *p_node_info; enum PrivacyNodeType media_type = PRIVACY_NODE_TYPE_NONE;
backend->mutex_.lock(); if (media_class == "Stream/Input/Video") {
if (backend->privacy_nodes.contains(id)) { media_type = PRIVACY_NODE_TYPE_VIDEO_INPUT;
p_node_info = &backend->privacy_nodes.at(id); } else if (media_class == "Stream/Input/Audio") {
media_type = PRIVACY_NODE_TYPE_AUDIO_INPUT;
} else if (media_class == "Stream/Output/Audio") {
media_type = PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
} else { } else {
p_node_info = new PrivacyNodeInfo(id, backend); return;
} }
backend->mutex_.unlock();
PipewireBackend *backend = static_cast<PipewireBackend *>(_data);
struct pw_proxy *proxy =
(pw_proxy *)pw_registry_bind(backend->registry, id, type, version, sizeof(PrivacyNodeInfo));
if (!proxy) return;
PrivacyNodeInfo *p_node_info = (PrivacyNodeInfo *)pw_proxy_get_user_data(proxy);
p_node_info->id = id;
p_node_info->data = backend;
p_node_info->type = media_type;
p_node_info->media_class = media_class;
pw_proxy_add_listener(proxy, &p_node_info->proxy_listener, &proxy_events, p_node_info); pw_proxy_add_listener(proxy, &p_node_info->proxy_listener, &proxy_events, p_node_info);
pw_proxy_add_object_listener(proxy, &p_node_info->object_listener, &node_events, p_node_info); pw_proxy_add_object_listener(proxy, &p_node_info->object_listener, &node_events, p_node_info);
}
backend->privacy_nodes.insert_or_assign(id, p_node_info);
} }
static void registry_event_global_remove(void *_data, uint32_t id) { static void registry_event_global_remove(void *_data, uint32_t id) {
auto backend = static_cast<PipewireBackend *>(_data); auto backend = static_cast<PipewireBackend *>(_data);
backend->mutex_.lock(); backend->mutex_.lock();
if (backend->privacy_nodes.contains(id)) { auto iter = backend->privacy_nodes.find(id);
if(iter != backend->privacy_nodes.end()) {
backend->privacy_nodes.erase(id); backend->privacy_nodes.erase(id);
} }
backend->mutex_.unlock(); backend->mutex_.unlock();