Skip to content

Commit f6ad617

Browse files
committed
service/pipewire: ignore insignificant device volume changes
Fixes devices getting stuck in a "waiting for volume change acknowledgement" state forever.
1 parent a116f39 commit f6ad617

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

src/services/pipewire/node.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,10 @@ void PwNodeBoundAudio::onInfo(const pw_node_info* info) {
228228

229229
if (param.id == SPA_PARAM_Props) {
230230
if ((param.flags & SPA_PARAM_INFO_READWRITE) == SPA_PARAM_INFO_READWRITE) {
231-
qCDebug(logNode) << "Enumerating props param for" << this;
231+
qCDebug(logNode) << "Enumerating props param for" << this->node;
232232
pw_node_enum_params(this->node->proxy(), 0, param.id, 0, UINT32_MAX, nullptr);
233233
} else {
234-
qCWarning(logNode) << "Unable to enumerate props param for" << this
234+
qCWarning(logNode) << "Unable to enumerate props param for" << this->node
235235
<< "as the param does not have read+write permissions.";
236236
}
237237
}
@@ -266,6 +266,10 @@ void PwNodeBoundAudio::updateVolumeProps(const spa_pod* param) {
266266
qCInfo(logNode) << "Got updated channels of" << this->node << '-' << this->mChannels;
267267
}
268268

269+
if (this->mServerVolumes != volumeProps.volumes) {
270+
this->mServerVolumes = volumeProps.volumes;
271+
}
272+
269273
if (this->mVolumes != volumeProps.volumes) {
270274
this->mVolumes = volumeProps.volumes;
271275
volumesChanged = true;
@@ -286,6 +290,7 @@ void PwNodeBoundAudio::updateVolumeProps(const spa_pod* param) {
286290
void PwNodeBoundAudio::onUnbind() {
287291
this->mChannels.clear();
288292
this->mVolumes.clear();
293+
this->mServerVolumes.clear();
289294
this->mDeviceVolumes.clear();
290295
this->waitingVolumes.clear();
291296
emit this->channelsChanged();
@@ -381,13 +386,32 @@ void PwNodeBoundAudio::setVolumes(const QVector<float>& volumes) {
381386
<< "via device";
382387
this->waitingVolumes = realVolumes;
383388
} else {
384-
qCInfo(logNode) << "Changing volumes of" << this->node << "to" << realVolumes << "via device";
385-
if (!this->node->device->setVolumes(this->node->routeDevice, realVolumes)) {
386-
return;
389+
auto significantChange = this->mServerVolumes.isEmpty();
390+
for (auto i = 0; i < this->mServerVolumes.length(); i++) {
391+
auto serverVolume = this->mServerVolumes.value(i);
392+
auto targetVolume = realVolumes.value(i);
393+
if (targetVolume == 0 || abs(targetVolume - serverVolume) >= 0.0001) {
394+
significantChange = true;
395+
break;
396+
}
387397
}
388398

389-
this->mDeviceVolumes = realVolumes;
390-
this->node->device->waitForDevice();
399+
if (significantChange) {
400+
qCInfo(logNode) << "Changing volumes of" << this->node << "to" << realVolumes
401+
<< "via device";
402+
if (!this->node->device->setVolumes(this->node->routeDevice, realVolumes)) {
403+
return;
404+
}
405+
406+
this->mDeviceVolumes = realVolumes;
407+
this->node->device->waitForDevice();
408+
} else {
409+
// Insignificant changes won't cause an info event on the device, leaving qs hung in the
410+
// "waiting for acknowledgement" state forever.
411+
qCInfo(logNode) << "Ignoring volume change for" << this->node << "to" << realVolumes
412+
<< "from" << this->mServerVolumes
413+
<< "as it is a device node and the change is too small.";
414+
}
391415
}
392416
} else {
393417
auto buffer = std::array<quint8, 1024>();

src/services/pipewire/node.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ private slots:
150150
bool mMuted = false;
151151
QVector<PwAudioChannel::Enum> mChannels;
152152
QVector<float> mVolumes;
153+
QVector<float> mServerVolumes;
153154
QVector<float> mDeviceVolumes;
154155
QVector<float> waitingVolumes;
155156
PwNode* node;

0 commit comments

Comments
 (0)