Add node volume

This commit is contained in:
Joey Yakimowich-Payne 2026-01-30 09:12:28 -07:00
commit e649dea9c1
3 changed files with 157 additions and 0 deletions

View file

@ -14,6 +14,8 @@
#include <pipewire/extensions/metadata.h>
#include <spa/param/audio/format-utils.h>
#include <spa/param/props.h>
#include <spa/pod/builder.h>
#include <spa/utils/defs.h>
#include <spa/utils/result.h>
@ -277,6 +279,8 @@ struct Client::Impl {
std::unordered_map<uint32_t, std::unique_ptr<StreamData>> virtual_streams;
std::unordered_map<uint32_t, std::unique_ptr<LinkProxy>> link_proxies;
std::unordered_map<uint32_t, VolumeState> volume_states;
uint32_t next_rule_id = 1;
std::unordered_map<uint32_t, RouteRule> route_rules;
std::vector<PendingAutoLink> pending_auto_links;
@ -1216,6 +1220,64 @@ Status Client::RemoveNode(NodeId node) {
return Status::Ok();
}
Status Client::SetNodeVolume(NodeId node, float volume, bool mute) {
Status status = impl_->EnsureConnected();
if (!status.ok()) {
return status;
}
if (node.value == 0) {
return Status::Error(StatusCode::kInvalidArgument, "invalid node id");
}
volume = std::clamp(volume, 0.0f, 1.5f);
pw_thread_loop_lock(impl_->thread_loop);
{
std::lock_guard<std::mutex> lock(impl_->cache_mutex);
if (impl_->nodes.find(node.value) == impl_->nodes.end()) {
pw_thread_loop_unlock(impl_->thread_loop);
return Status::Error(StatusCode::kNotFound, "node not found");
}
}
auto* proxy = static_cast<pw_node*>(
pw_registry_bind(impl_->registry, node.value,
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0));
if (!proxy) {
pw_thread_loop_unlock(impl_->thread_loop);
return Status::Error(StatusCode::kInternal, "failed to bind node proxy");
}
uint8_t buffer[128];
spa_pod_builder builder = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
auto* param = reinterpret_cast<const spa_pod*>(spa_pod_builder_add_object(
&builder,
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
SPA_PROP_volume, SPA_POD_Float(volume),
SPA_PROP_mute, SPA_POD_Bool(mute)));
pw_node_set_param(proxy, SPA_PARAM_Props, 0, param);
pw_proxy_destroy(reinterpret_cast<pw_proxy*>(proxy));
{
std::lock_guard<std::mutex> lock(impl_->cache_mutex);
impl_->volume_states[node.value] = VolumeState{volume, mute};
}
pw_thread_loop_unlock(impl_->thread_loop);
return Status::Ok();
}
Result<VolumeState> Client::GetNodeVolume(NodeId node) const {
std::lock_guard<std::mutex> lock(impl_->cache_mutex);
auto it = impl_->volume_states.find(node.value);
if (it == impl_->volume_states.end()) {
return {Status::Ok(), VolumeState{}};
}
return {Status::Ok(), it->second};
}
Result<Link> Client::CreateLink(PortId output, PortId input, const LinkOptions& options) {
Status status = impl_->EnsureConnected();
if (!status.ok()) {
@ -1719,6 +1781,30 @@ size_t Client::Test_GetPendingAutoLinkCount() const {
std::lock_guard<std::mutex> lock(impl_->cache_mutex);
return impl_->pending_auto_links.size();
}
Status Client::Test_SetNodeVolume(NodeId node, float volume, bool mute) {
if (!impl_) {
return Status::Error(StatusCode::kUnavailable, "no impl");
}
std::lock_guard<std::mutex> lock(impl_->cache_mutex);
if (impl_->nodes.find(node.value) == impl_->nodes.end()) {
return Status::Error(StatusCode::kNotFound, "node not found");
}
impl_->volume_states[node.value] = VolumeState{std::clamp(volume, 0.0f, 1.5f), mute};
return Status::Ok();
}
Result<VolumeState> Client::Test_GetNodeVolume(NodeId node) const {
if (!impl_) {
return {Status::Error(StatusCode::kUnavailable, "no impl"), {}};
}
std::lock_guard<std::mutex> lock(impl_->cache_mutex);
auto it = impl_->volume_states.find(node.value);
if (it == impl_->volume_states.end()) {
return {Status::Ok(), VolumeState{}};
}
return {Status::Ok(), it->second};
}
#endif
} // namespace warppipe