https://bugs.kde.org/show_bug.cgi?id=525548

--- Comment #1 from Sergey <[email protected]> ---
Correction to the reproduction steps, with the measurements behind it.

After filing this I tried to reproduce the wireplumber churn deterministically,
and it did
NOT reproduce. I am posting the negative result because the steps in comment 0
are probably
wrong, and I do not want to send anyone chasing them.

HOW I TESTED

I did not drive plasmashell. I wrote a small standalone client that uses the
same
PulseAudioQt::Context the applet uses, linked against the installed
libKF6PulseAudioQt.so.5 (pulseaudio-qt 1.8.1), and ran it for the whole session
while the
audio stack was cycled underneath it. It logs every stateChanged,
autoConnectingChanged,
sinkAdded and sinkRemoved together with the resulting model size, so the client
model can be
compared against the server's actual object set at any moment.

Everything ran inside its own dbus-run-session with a private XDG_RUNTIME_DIR,
so the
machine's real session was never touched. Server truth was read with pactl in
the same
sandbox.

Real ALSA hardware was present in the sandbox, not just the dummy device -
pactl showed
alsa_output.usb-C-Media_...Lunacy_Louder...analog-stereo and
alsa_output.pci-0000_00_1f.3.analog-stereo. (My first attempt only had
auto_null, i.e.
module-always-sink's dummy, and was meaningless; I redid it after checking
pw-dump showed
the real nodes coming up.)

TEST A - the scenario from comment 0 (only wireplumber cycled)

pipewire and pipewire-pulse stayed up the whole time; wireplumber was stopped
and started 5
times, 6 s down / 15 s up each cycle. This is what a session-switch helper
does.

Result: no duplicates, 5 cycles out of 5. Model size tracked the server
exactly:

  cycle 1: sinkRemoved pci index=61 -> count=1
           sinkRemoved usb index=57 -> count=0
           sinkAdded   auto_null    -> count=1
           sinkRemoved auto_null    -> count=0
           sinkAdded   usb index=108 -> count=1
           sinkAdded   pci index=113 -> count=2
  ...same shape for cycles 2-5, ending at count=2

state was Ready(4) throughout, autoConnecting never went to 1, no Failed state.
With
pipewire-pulse alive the client context is never torn down, so every removal
and addition
is delivered normally and the model stays consistent. I now doubt that
wireplumber churn
alone can produce the duplicates reported here.

TEST B - restarting the audio server itself

Same client, but pipewire-pulse was killed for >25 s and then restarted, twice.
This DID
produce a stale entry:

  T+125033ms | EVENT sinkAdded name='auto_null' index=33 -> count=2
            |   sink name='auto_null' index=34
            |   sink name='auto_null' index=33   <- stale, left over

Server truth at that moment (pactl list short sinks): a single entry, index 34.
So the
client model had one object the server did not.

That matches the retry logic in pulseaudio-qt's context.cpp (checked against
tag v1.8.1):
on a bad state, reset() - which is what clears the model - is only called if
retries are
still left:

    } else if (!PA_CONTEXT_IS_GOOD(state)) {
        if (!m_connectTimer.isActive() && hasConnectionTriesLeft()) {
            reset();
            m_connectTimer.start(std::chrono::seconds(5));

maxTries is 5 with a 5 s timer, so after roughly 25 s of downtime the condition
is false,
reset() is skipped, and objects from the previous connection survive while new
ones are
added on top.

Two things I also observed and cannot explain yet: the client recovers on its
own via the
QDBusServiceWatcher even after giving up (so auto-reconnect is not permanently
disabled),
and in test B the second outage produced state=Failed(5) with autoConnecting=0,
i.e. it did
not retry at all in that window.

CAVEAT - what this does and does not prove

This exercises PulseAudioQt::Context only. The applet additionally goes through
QML model
classes (PulseObjectFilterModel) and a kded proxy (kded.contextConnected).
Duplicates could
live in that layer, and I have not tested it. So: the base context model does
not duplicate
on wireplumber churn, but I cannot rule out that the applet still does.

I will come back with the applet-layer result. If it turns out duplicates only
appear on a
server restart, this bug would be about the skip of reset() above rather than
about device
churn, and I am happy to have it retitled or moved.

I kept the harness and the full raw logs of both tests, and can attach them
here if that helps.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to