fix(pipewire): match route mute to profile device - #3873
Conversation
[P2] Match the availability check to profileDevice tooFile: src/pipewire/pipewire_service.cpp:1615-1622 The new selector correctly returns nullptr when the card has no route matching nd->profileDevice. However, hasDirRoutes still treats any same-direction card route as relevant: activeRoute = activeAudioDeviceRoute(device->routes, wantDir, nd->profileDevice);
// ...
std::ranges::any_of(device->routes, matchesDir)Consequently, a valid node without its own card route is marked unavailable whenever the card contains an unrelated This affects route-less profiles such as Pro Audio and can also surface with retained routes after a profile change. The device-side route-presence predicate should apply the same profileDevice condition as activeAudioDeviceRoute;
The added test’s unmatched-device case only checks that the selector returns nullptr, so it misses the resulting Verification: Reproduced the exact selector/caller state: matching_route=null, has_direction_route=true, |
Summary
card.profile.deviceProblem
A PipeWire card's
ParamRoutetable can contain several routes in the same direction. The existing selector chooses the highest-priority route for that direction without checking which profile device owns it.On an ASUS ProArt PX13, the active speaker node has
card.profile.device = 0, while the inactive headphone route hasdevice = 1, a higher priority and a stored mute. Noctalia therefore shows the unmuted speakers as muted. The same mismatch affects the internal microphone when the inactive headset-microphone route is muted.This change records
card.profile.devicefrom node properties and uses it when selecting a route from the owning card. Node-local route lists retain their existing direction-only selection.Testing
audio_route_selection: passesmain: 79/80 passprocessfailure (completion-only async command stdout was wrong) reproduces on cleanmainafter stashing this changewpctl