From 23f0acfd1d141b6157267604f856c962cd537a6c Mon Sep 17 00:00:00 2001 From: fuleyi Date: Thu, 30 Oct 2025 20:23:40 +0800 Subject: [PATCH] pulse-server: Fix missing subscription events on device port changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a device profile changes (e.g., Bluetooth headset switching from a2dp-sink to headset-head-unit), the active port information changes but PulseAudio compatibility layer clients don't receive the expected PA_SUBSCRIPTION_EVENT_SOURCE or PA_SUBSCRIPTION_EVENT_SINK change events. Root cause: The collect_device_info() function updates the active_port index from SPA_PARAM_Route parameters, but doesn't update the corresponding active_port_name field. When update_device_info() uses memcmp() to detect changes in the device_info structure, it compares the entire structure including active_port_name. If the pointer value doesn't change (even though the actual port changed), no change is detected, and the change_mask flag (PW_MANAGER_OBJECT_FLAG_SOURCE/SINK) is not set, preventing subscription events from being sent. Solution: After setting active_port in collect_device_info(), look up the corresponding port name from SPA_PARAM_EnumRoute parameters by matching both the port index and direction. Initialize active_port_name to NULL at the start to ensure it's always recalculated. This fix applies to all device types (Bluetooth, USB, PCI sound cards) and all profile switching scenarios, ensuring applications using the PulseAudio compatibility layer receive proper device change notifications. Tested with: - Bluetooth headset profile switching (a2dp-sink ↔ headset-head-unit) - Applications subscribing to PA_SUBSCRIPTION_MASK_SOURCE/SINK events - Verified no regression in audio initialization --- src/modules/module-protocol-pulse/collect.c | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/modules/module-protocol-pulse/collect.c b/src/modules/module-protocol-pulse/collect.c index 300eee262..d24608b98 100644 --- a/src/modules/module-protocol-pulse/collect.c +++ b/src/modules/module-protocol-pulse/collect.c @@ -233,6 +233,7 @@ static void collect_device_info(struct pw_manager_object *device, struct pw_mana struct device_info *dev_info, bool monitor, struct defs *defs) { struct pw_manager_param *p; + dev_info->active_port_name = NULL; if (card) { spa_list_for_each(p, &card->param_list, link) { @@ -256,6 +257,30 @@ static void collect_device_info(struct pw_manager_object *device, struct pw_mana dev_info->have_volume = true; } } + + /* Look up the port name for the active port */ + if (dev_info->active_port != SPA_ID_INVALID) { + spa_list_for_each(p, &card->param_list, link) { + uint32_t index, direction; + const char *name = NULL; + + if (p->id != SPA_PARAM_EnumRoute) + continue; + + if (spa_pod_parse_object(p->param, + SPA_TYPE_OBJECT_ParamRoute, NULL, + SPA_PARAM_ROUTE_index, SPA_POD_Int(&index), + SPA_PARAM_ROUTE_direction, SPA_POD_Id(&direction), + SPA_PARAM_ROUTE_name, SPA_POD_String(&name)) < 0) + continue; + + if (index == dev_info->active_port && + direction == dev_info->direction) { + dev_info->active_port_name = name; + break; + } + } + } } spa_list_for_each(p, &device->param_list, link) {