From afcb91f59b7951ac7e455d260f10cb11024d10fc Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Thu, 20 Jun 2024 08:42:27 -0400 Subject: [PATCH] rescan: Stop rescan for 2s if BT node is removed The intention here is to fix a Bluetooth bug where changing between different profiles momentarily causes streams to be linked to an internal speaker. Unfortunately, this case is not handled by the event dispatcher because some signals are emitted using idle callbacks, and therefore we have to rely on extra logic in rescan.lua to solve the problem. --- src/scripts/linking/rescan.lua | 61 +++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/scripts/linking/rescan.lua b/src/scripts/linking/rescan.lua index bdc01268..368d824b 100644 --- a/src/scripts/linking/rescan.lua +++ b/src/scripts/linking/rescan.lua @@ -15,6 +15,8 @@ cutils = require ("common-utils") futils = require ("filter-utils") log = Log.open_topic ("s-linking") handles = {} +handles.rescan_enabled = true +handles.timeout_source = nil function checkFilter (si, om, handle_nonstreams) -- always handle filters if handle_nonstreams is true, even if it is disabled @@ -192,8 +194,65 @@ SimpleEventHook { }, }, execute = function (event) + if handles.rescan_enabled then + local source = event:get_source () + source:call ("schedule-rescan", "linking") + end + end +}:register () + +SimpleEventHook { + name = "linking/session-item-added", + before = "linking/rescan-trigger", + interests = { + EventInterest { + Constraint { "event.type", "=", "session-item-added" }, + }, + }, + execute = function (event) + -- clear timeout source, if any + if handles.timeout_source ~= nil then + handles.timeout_source:destroy () + handles.timeout_source = nil + end + + -- Always enable rescan when any node is added + handles.rescan_enabled = true + end +}:register () + +-- Stop rescan for 2 seconds if BT item was removed. This avoids audio +-- being played on internal nodes for a few seconds while the BT device is +-- switching profiles. +SimpleEventHook { + name = "linking/bluez-session-item-removed", + before = "linking/rescan-trigger", + interests = { + EventInterest { + Constraint { "event.type", "=", "session-item-removed" }, + Constraint { "device.api", "=", "bluez5" }, + }, + }, + execute = function (event) + local si = event:get_subject () + local si_props = si.properties local source = event:get_source () - source:call ("schedule-rescan", "linking") + + -- clear timeout source, if any + if handles.timeout_source ~= nil then + handles.timeout_source:destroy () + handles.timeout_source = nil + end + + -- disable rescan + handles.rescan_enabled = false + + -- re-enable rescan after 2 seconds + handles.timeout_source = Core.timeout_add (2000, function() + handles.timeout_source = nil + handles.rescan_enabled = true + source:call ("schedule-rescan", "linking") + end) end }:register ()