From ad45683f21769bb554afcd6f908b828331ad0034 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Fri, 30 Jan 2026 13:32:07 -0700 Subject: [PATCH] Fix race where competing-link sweep destroys auto-links before .bound fires ProcessSavedLinks checked auto_link_proxies by global ID (proxy->id), but this is only set asynchronously in the .bound callback. On a second CoreDone pass (e.g. when virtual Sink ports appear), the sweep could classify a just-created rule link as competing and destroy it. Track (output_port, input_port) on LinkProxy at creation time and match by port pair instead of the racy global ID. --- src/warppipe.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/warppipe.cpp b/src/warppipe.cpp index a0bd0dd..9a97e9d 100644 --- a/src/warppipe.cpp +++ b/src/warppipe.cpp @@ -125,6 +125,8 @@ struct LinkProxy { bool failed = false; std::string error; uint32_t id = SPA_ID_INVALID; + uint32_t output_port = 0; + uint32_t input_port = 0; }; void LinkProxyBound(void* data, uint32_t global_id) { @@ -1026,6 +1028,8 @@ void Client::Impl::CreateAutoLinkAsync(uint32_t output_port, uint32_t input_port auto link_data = std::make_unique(); link_data->proxy = proxy; link_data->loop = thread_loop; + link_data->output_port = output_port; + link_data->input_port = input_port; pw_proxy_add_listener(proxy, &link_data->listener, &kLinkProxyEvents, link_data.get()); std::lock_guard lock(cache_mutex); @@ -1122,13 +1126,17 @@ void Client::Impl::ProcessSavedLinks() { } } if (!is_ours) { + uint32_t out_port = link_entry.second.output_port.value; for (const auto& proxy : auto_link_proxies) { - if (proxy && proxy->id == link_id) { is_ours = true; break; } + if (proxy && proxy->output_port == out_port && + proxy->input_port == in_port) { is_ours = true; break; } } } if (!is_ours) { + uint32_t out_port = link_entry.second.output_port.value; for (const auto& proxy : saved_link_proxies) { - if (proxy && proxy->id == link_id) { is_ours = true; break; } + if (proxy && proxy->output_port == out_port && + proxy->input_port == in_port) { is_ours = true; break; } } } if (!is_ours) { @@ -1167,6 +1175,8 @@ void Client::Impl::CreateSavedLinkAsync(uint32_t output_port, auto link_data = std::make_unique(); link_data->proxy = proxy; link_data->loop = thread_loop; + link_data->output_port = output_port; + link_data->input_port = input_port; pw_proxy_add_listener(proxy, &link_data->listener, &kLinkProxyEvents, link_data.get()); @@ -1874,6 +1884,8 @@ Result Client::CreateLink(PortId output, PortId input, const LinkOptions& auto link_proxy = std::make_unique(); link_proxy->proxy = proxy; link_proxy->loop = impl_->thread_loop; + link_proxy->output_port = output.value; + link_proxy->input_port = input.value; pw_proxy_add_listener(proxy, &link_proxy->listener, &kLinkProxyEvents, link_proxy.get()); int wait_attempts = 0;