Issue-3092 Add source support to wireplumber module

- Adds microphone support etc to the wireplumber module.

  The existing module hardcodes the selected node type to "Audio/Sink". This feature allows the user to override this
  via `"node-type": "Audio/Source"`.

- Unlike the pulseaudio module, this change does not try to see the module manage both input and output. The same effect
  can be achieved by running two instances of the wireplumber module.

  This approach:
  - Works around some of the complexity overhead that seem to have caused similar PRs to stall.
  - Using separate module instances also allows both the microphone and speaker levels to be controlled with a scroll
    wheel. This is something a unified module like pulseaudio struggles with.
  - Similarly, separate instances allows the source volume level to be exposed as the state. Ie- the linear-gradient
    css patterns can be applied to both input and output.
This commit is contained in:
Rowan Leeder
2024-09-25 03:16:14 +10:00
parent 07f75e303c
commit 71a53eb79d
3 changed files with 40 additions and 7 deletions

View File

@ -16,13 +16,17 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
muted_(false),
volume_(0.0),
min_step_(0.0),
node_id_(0) {
node_id_(0),
type_(nullptr) {
wp_init(WP_INIT_PIPEWIRE);
wp_core_ = wp_core_new(nullptr, nullptr, nullptr);
apis_ = g_ptr_array_new_with_free_func(g_object_unref);
om_ = wp_object_manager_new();
prepare();
type_ = g_strdup(config_["node-type"].isString() ? config_["node-type"].asString().c_str()
: "Audio/Sink");
prepare(this);
spdlog::debug("[{}]: connecting to pipewire...", name_);
@ -46,6 +50,7 @@ waybar::modules::Wireplumber::~Wireplumber() {
g_clear_object(&mixer_api_);
g_clear_object(&def_nodes_api_);
g_free(default_node_name_);
g_free(type_);
}
void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber* self, uint32_t id) {
@ -138,7 +143,7 @@ void waybar::modules::Wireplumber::onDefaultNodesApiChanged(waybar::modules::Wir
spdlog::debug("[{}]: (onDefaultNodesApiChanged)", self->name_);
uint32_t defaultNodeId;
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", "Audio/Sink", &defaultNodeId);
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", self->type_, &defaultNodeId);
if (!isValidNodeId(defaultNodeId)) {
spdlog::warn("[{}]: '{}' is not a valid node ID. Ignoring node change.", self->name_,
@ -200,9 +205,9 @@ void waybar::modules::Wireplumber::onObjectManagerInstalled(waybar::modules::Wir
throw std::runtime_error("Mixer api is not loaded\n");
}
g_signal_emit_by_name(self->def_nodes_api_, "get-default-configured-node-name", "Audio/Sink",
g_signal_emit_by_name(self->def_nodes_api_, "get-default-configured-node-name", self->type_,
&self->default_node_name_);
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", "Audio/Sink", &self->node_id_);
g_signal_emit_by_name(self->def_nodes_api_, "get-default-node", self->type_, &self->node_id_);
if (self->default_node_name_ != nullptr) {
spdlog::debug("[{}]: (onObjectManagerInstalled) - default configured node name: {} and id: {}",
@ -246,7 +251,7 @@ void waybar::modules::Wireplumber::activatePlugins() {
void waybar::modules::Wireplumber::prepare() {
spdlog::debug("[{}]: preparing object manager", name_);
wp_object_manager_add_interest(om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class",
"=s", "Audio/Sink", nullptr);
"=s", self->type_, nullptr);
}
void waybar::modules::Wireplumber::onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res,