service/pipewire: ignore insignificant device volume changes

Fixes devices getting stuck in a "waiting for volume change
acknowledgement" state forever.
This commit is contained in:
outfoxxed 2024-08-29 13:17:24 -07:00
parent a116f39c63
commit f6ad617b67
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
2 changed files with 32 additions and 7 deletions

View file

@ -228,10 +228,10 @@ void PwNodeBoundAudio::onInfo(const pw_node_info* info) {
if (param.id == SPA_PARAM_Props) {
if ((param.flags & SPA_PARAM_INFO_READWRITE) == SPA_PARAM_INFO_READWRITE) {
qCDebug(logNode) << "Enumerating props param for" << this;
qCDebug(logNode) << "Enumerating props param for" << this->node;
pw_node_enum_params(this->node->proxy(), 0, param.id, 0, UINT32_MAX, nullptr);
} else {
qCWarning(logNode) << "Unable to enumerate props param for" << this
qCWarning(logNode) << "Unable to enumerate props param for" << this->node
<< "as the param does not have read+write permissions.";
}
}
@ -266,6 +266,10 @@ void PwNodeBoundAudio::updateVolumeProps(const spa_pod* param) {
qCInfo(logNode) << "Got updated channels of" << this->node << '-' << this->mChannels;
}
if (this->mServerVolumes != volumeProps.volumes) {
this->mServerVolumes = volumeProps.volumes;
}
if (this->mVolumes != volumeProps.volumes) {
this->mVolumes = volumeProps.volumes;
volumesChanged = true;
@ -286,6 +290,7 @@ void PwNodeBoundAudio::updateVolumeProps(const spa_pod* param) {
void PwNodeBoundAudio::onUnbind() {
this->mChannels.clear();
this->mVolumes.clear();
this->mServerVolumes.clear();
this->mDeviceVolumes.clear();
this->waitingVolumes.clear();
emit this->channelsChanged();
@ -381,13 +386,32 @@ void PwNodeBoundAudio::setVolumes(const QVector<float>& volumes) {
<< "via device";
this->waitingVolumes = realVolumes;
} else {
qCInfo(logNode) << "Changing volumes of" << this->node << "to" << realVolumes << "via device";
if (!this->node->device->setVolumes(this->node->routeDevice, realVolumes)) {
return;
auto significantChange = this->mServerVolumes.isEmpty();
for (auto i = 0; i < this->mServerVolumes.length(); i++) {
auto serverVolume = this->mServerVolumes.value(i);
auto targetVolume = realVolumes.value(i);
if (targetVolume == 0 || abs(targetVolume - serverVolume) >= 0.0001) {
significantChange = true;
break;
}
}
this->mDeviceVolumes = realVolumes;
this->node->device->waitForDevice();
if (significantChange) {
qCInfo(logNode) << "Changing volumes of" << this->node << "to" << realVolumes
<< "via device";
if (!this->node->device->setVolumes(this->node->routeDevice, realVolumes)) {
return;
}
this->mDeviceVolumes = realVolumes;
this->node->device->waitForDevice();
} else {
// Insignificant changes won't cause an info event on the device, leaving qs hung in the
// "waiting for acknowledgement" state forever.
qCInfo(logNode) << "Ignoring volume change for" << this->node << "to" << realVolumes
<< "from" << this->mServerVolumes
<< "as it is a device node and the change is too small.";
}
}
} else {
auto buffer = std::array<quint8, 1024>();

View file

@ -150,6 +150,7 @@ private:
bool mMuted = false;
QVector<PwAudioChannel::Enum> mChannels;
QVector<float> mVolumes;
QVector<float> mServerVolumes;
QVector<float> mDeviceVolumes;
QVector<float> waitingVolumes;
PwNode* node;