Summary
Follow-up nit from the review of #3630 (AudioOutputRouter, part of #3306). Non-urgent.
AudioOutputRouter never prunes followers whose QPointer guard has gone null. When a registered sink is destroyed before the router, its entry stays in m_followers as a no-op closure that is still iterated (and skipped) on every setCurrentDevice() fan-out.
Why it's harmless today
The router is register-once-at-startup with exactly two followers (ClientPuduMonitor, QsoRecorder), both owned for the app lifetime, and the guarded lambda is correct (it just does nothing when null). So there's no functional bug and no meaningful cost right now.
Why it's worth tidying
The accumulation only matters if the registry ever gains dynamically created/destroyed followers (e.g. a future per-receiver or WebSDR-sourced sink — see the aux-output-sink work queued in docs/audio-sink-factory.md). Then stale null entries would grow unbounded.
Proposed fix
Either:
- Prune during fan-out — drop entries whose guard is null while iterating the snapshot (compact
m_followers after the loop), or
- Add a
removeFollower() / return a small handle from addFollower() for explicit deregistration.
The std::function overload has no guard, so a handle/removeFollower is the more general answer if dynamic followers ever land.
References
Summary
Follow-up nit from the review of #3630 (AudioOutputRouter, part of #3306). Non-urgent.
AudioOutputRouternever prunes followers whoseQPointerguard has gone null. When a registered sink is destroyed before the router, its entry stays inm_followersas a no-op closure that is still iterated (and skipped) on everysetCurrentDevice()fan-out.Why it's harmless today
The router is register-once-at-startup with exactly two followers (
ClientPuduMonitor,QsoRecorder), both owned for the app lifetime, and the guarded lambda is correct (it just does nothing when null). So there's no functional bug and no meaningful cost right now.Why it's worth tidying
The accumulation only matters if the registry ever gains dynamically created/destroyed followers (e.g. a future per-receiver or WebSDR-sourced sink — see the aux-output-sink work queued in
docs/audio-sink-factory.md). Then stale null entries would grow unbounded.Proposed fix
Either:
m_followersafter the loop), orremoveFollower()/ return a small handle fromaddFollower()for explicit deregistration.The
std::functionoverload has no guard, so a handle/removeFolloweris the more general answer if dynamic followers ever land.References
src/core/AudioOutputRouter.{h,cpp}