mirror of
https://git.outfoxxed.me/quickshell/quickshell.git
synced 2026-02-23 03:33:57 +11:00
services/pipewire: use node volume control when device missing
Some outputs which present a pipewire device object do not present routes, instead expecting volume to be set on the associated pipewire node.
This commit is contained in:
parent
dacfa9de82
commit
afbc5ffd4e
5 changed files with 35 additions and 14 deletions
|
|
@ -36,6 +36,7 @@ set shell id.
|
||||||
|
|
||||||
- Fixed volume control breaking with pipewire pro audio mode.
|
- Fixed volume control breaking with pipewire pro audio mode.
|
||||||
- Fixed volume control breaking with bluez streams and potentially others.
|
- Fixed volume control breaking with bluez streams and potentially others.
|
||||||
|
- Fixed volume control breaking for devices without route definitions.
|
||||||
- Fixed escape sequence handling in desktop entries.
|
- Fixed escape sequence handling in desktop entries.
|
||||||
- Fixed volumes not initializing if a pipewire device was already loaded before its node.
|
- Fixed volumes not initializing if a pipewire device was already loaded before its node.
|
||||||
- Fixed hyprland active toplevel not resetting after window closes.
|
- Fixed hyprland active toplevel not resetting after window closes.
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,10 @@ bool PwDevice::tryLoadVolumeProps(qint32 routeDevice, PwVolumeProps& volumeProps
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PwDevice::hasRouteDevice(qint32 routeDevice) const {
|
||||||
|
return this->routeDeviceIndexes.contains(routeDevice);
|
||||||
|
}
|
||||||
|
|
||||||
void PwDevice::polled() {
|
void PwDevice::polled() {
|
||||||
// It is far more likely that the list content has not come in yet than it having no entries,
|
// It is far more likely that the list content has not come in yet than it having no entries,
|
||||||
// and there isn't a way to check in the case that there *aren't* actually any entries.
|
// and there isn't a way to check in the case that there *aren't* actually any entries.
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,15 @@
|
||||||
#include <spa/pod/builder.h>
|
#include <spa/pod/builder.h>
|
||||||
|
|
||||||
#include "core.hpp"
|
#include "core.hpp"
|
||||||
#include "node.hpp"
|
|
||||||
#include "registry.hpp"
|
#include "registry.hpp"
|
||||||
|
|
||||||
namespace qs::service::pipewire {
|
namespace qs::service::pipewire {
|
||||||
|
|
||||||
class PwDevice;
|
class PwDevice;
|
||||||
|
|
||||||
|
// Forward declare to avoid circular dependency with node.hpp
|
||||||
|
struct PwVolumeProps;
|
||||||
|
|
||||||
class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSION_DEVICE> {
|
class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSION_DEVICE> {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
|
|
@ -33,6 +35,7 @@ public:
|
||||||
[[nodiscard]] bool waitingForDevice() const;
|
[[nodiscard]] bool waitingForDevice() const;
|
||||||
|
|
||||||
[[nodiscard]] bool tryLoadVolumeProps(qint32 routeDevice, PwVolumeProps& volumeProps);
|
[[nodiscard]] bool tryLoadVolumeProps(qint32 routeDevice, PwVolumeProps& volumeProps);
|
||||||
|
[[nodiscard]] bool hasRouteDevice(qint32 routeDevice) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceReady();
|
void deviceReady();
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,10 @@ void PwNodeBoundAudio::setMuted(bool muted) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float PwNodeBoundAudio::averageVolume() const {
|
float PwNodeBoundAudio::averageVolume() const {
|
||||||
|
if (this->mVolumes.isEmpty()) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
float total = 0;
|
float total = 0;
|
||||||
|
|
||||||
for (auto volume: this->mVolumes) {
|
for (auto volume: this->mVolumes) {
|
||||||
|
|
@ -572,22 +576,28 @@ PwVolumeProps PwVolumeProps::parseSpaPod(const spa_pod* param) {
|
||||||
const auto* muteProp = spa_pod_find_prop(param, nullptr, SPA_PROP_mute);
|
const auto* muteProp = spa_pod_find_prop(param, nullptr, SPA_PROP_mute);
|
||||||
const auto* volumeStepProp = spa_pod_find_prop(param, nullptr, SPA_PROP_volumeStep);
|
const auto* volumeStepProp = spa_pod_find_prop(param, nullptr, SPA_PROP_volumeStep);
|
||||||
|
|
||||||
const auto* volumes = reinterpret_cast<const spa_pod_array*>(&volumesProp->value);
|
if (volumesProp) {
|
||||||
const auto* channels = reinterpret_cast<const spa_pod_array*>(&channelsProp->value);
|
const auto* volumes = reinterpret_cast<const spa_pod_array*>(&volumesProp->value);
|
||||||
|
spa_pod* iter = nullptr;
|
||||||
spa_pod* iter = nullptr;
|
SPA_POD_ARRAY_FOREACH(volumes, iter) {
|
||||||
SPA_POD_ARRAY_FOREACH(volumes, iter) {
|
// Cubing behavior found in MPD source, and appears to corrospond to everyone else's measurements correctly.
|
||||||
// Cubing behavior found in MPD source, and appears to corrospond to everyone else's measurements correctly.
|
auto linear = *reinterpret_cast<float*>(iter);
|
||||||
auto linear = *reinterpret_cast<float*>(iter);
|
auto visual = std::cbrt(linear);
|
||||||
auto visual = std::cbrt(linear);
|
props.volumes.push_back(visual);
|
||||||
props.volumes.push_back(visual);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPA_POD_ARRAY_FOREACH(channels, iter) {
|
if (channelsProp) {
|
||||||
props.channels.push_back(*reinterpret_cast<PwAudioChannel::Enum*>(iter));
|
const auto* channels = reinterpret_cast<const spa_pod_array*>(&channelsProp->value);
|
||||||
|
spa_pod* iter = nullptr;
|
||||||
|
SPA_POD_ARRAY_FOREACH(channels, iter) {
|
||||||
|
props.channels.push_back(*reinterpret_cast<PwAudioChannel::Enum*>(iter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spa_pod_get_bool(&muteProp->value, &props.mute);
|
if (muteProp) {
|
||||||
|
spa_pod_get_bool(&muteProp->value, &props.mute);
|
||||||
|
}
|
||||||
|
|
||||||
if (volumeStepProp) {
|
if (volumeStepProp) {
|
||||||
spa_pod_get_float(&volumeStepProp->value, &props.volumeStep);
|
spa_pod_get_float(&volumeStepProp->value, &props.volumeStep);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <spa/pod/pod.h>
|
#include <spa/pod/pod.h>
|
||||||
|
|
||||||
#include "core.hpp"
|
#include "core.hpp"
|
||||||
|
#include "device.hpp"
|
||||||
#include "registry.hpp"
|
#include "registry.hpp"
|
||||||
|
|
||||||
namespace qs::service::pipewire {
|
namespace qs::service::pipewire {
|
||||||
|
|
@ -249,7 +250,9 @@ public:
|
||||||
bool proAudio = false;
|
bool proAudio = false;
|
||||||
|
|
||||||
[[nodiscard]] bool shouldUseDevice() const {
|
[[nodiscard]] bool shouldUseDevice() const {
|
||||||
return this->device && !this->proAudio && this->routeDevice != -1;
|
if (!this->device || this->proAudio || this->routeDevice == -1) return false;
|
||||||
|
// Only use device control if the device actually has route indexes for this routeDevice
|
||||||
|
return this->device->hasRouteDevice(this->routeDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue