mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-08 17:28:38 +02:00
policy-{bluetooth|device-profile|device-routes}.lua: Optimize for Event stack
- Sharpen the hooks. - Make settings live, apply them when they are changed. - Move some of the common functions to common_utils.lua
This commit is contained in:
parent
8e7611fa9f
commit
6762de3990
7 changed files with 158 additions and 170 deletions
|
|
@ -287,7 +287,13 @@ wp_default_profile_enable (WpPlugin * plugin, WpTransition * transition)
|
|||
wp_interest_event_hook_add_interest (WP_INTEREST_EVENT_HOOK (hook),
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "event.type", "=s", "params-changed",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "event.subject.type", "=s", "device",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "event.subject.param-id", "=s", "EnumProfile",
|
||||
NULL);
|
||||
wp_interest_event_hook_add_interest (WP_INTEREST_EVENT_HOOK (hook),
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "event.type", "=s", "params-changed",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "event.subject.type", "=s", "device",
|
||||
WP_CONSTRAINT_TYPE_PW_PROPERTY, "event.subject.param-id", "=s", "Profile",
|
||||
NULL);
|
||||
wp_event_dispatcher_register_hook (dispatcher, hook);
|
||||
g_clear_object (&hook);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,28 @@ function cutils.parseArray (str, convert_value, with_type)
|
|||
return array
|
||||
end
|
||||
|
||||
function cutils.arrayContains (a, value)
|
||||
for _, v in ipairs (a) do
|
||||
if v == value then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function cutils.storeAfterTimeout (state, state_table)
|
||||
if timeout_source then
|
||||
timeout_source:destroy ()
|
||||
end
|
||||
local timeout_source = Core.timeout_add (1000, function ()
|
||||
local saved, err = state:save (state_table)
|
||||
if not saved then
|
||||
Log.warning (err)
|
||||
end
|
||||
timeout_source = nil
|
||||
end)
|
||||
end
|
||||
|
||||
cutils.default_metadata_om:activate ()
|
||||
|
||||
return cutils
|
||||
|
|
@ -256,7 +256,8 @@ function putils.haveAvailableRoutes (si_props)
|
|||
goto skip_enum_route
|
||||
end
|
||||
|
||||
if not arrayContains (route.devices, tonumber (card_profile_device)) then
|
||||
if not cutils.arrayContains
|
||||
(route.devices, tonumber (card_profile_device)) then
|
||||
goto skip_enum_route
|
||||
end
|
||||
found = found + 1;
|
||||
|
|
|
|||
|
|
@ -26,10 +26,50 @@
|
|||
|
||||
-- settings file: policy.conf
|
||||
|
||||
local use_persistent_storage =
|
||||
Settings.parse_boolean_safe ("bt-policy-use-persistent-storage", false)
|
||||
local use_headset_profile =
|
||||
Settings.parse_boolean_safe ("bt-policy-media-role.use-headset-profile", true)
|
||||
local cutils = require ("common-utils")
|
||||
|
||||
local use_persistent_storage = Settings.parse_boolean_safe
|
||||
("policy.bluetooth.use-persistent-storage", false)
|
||||
local use_headset_profile = Settings.parse_boolean_safe
|
||||
("policy.bluetooth.media-role.use-headset-profile", true)
|
||||
local apps_setting = Settings.parse_array_safe
|
||||
("policy.bluetooth.media-role.applications")
|
||||
|
||||
state = nil
|
||||
headset_profiles = nil
|
||||
|
||||
function handlePersistantSetting (enable)
|
||||
if enable and state == nil then
|
||||
-- the state storage
|
||||
state = use_persistent_storage and State ("policy-bluetooth") or nil
|
||||
headset_profiles = state and state:load () or {}
|
||||
else
|
||||
state = nil
|
||||
headset_profiles = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function settingsChangedCallback (_, setting, _)
|
||||
if setting == "policy.bluetooth.use-persistent-storage" then
|
||||
use_persistent_storage = Settings.parse_boolean_safe
|
||||
("policy.bluetooth.use-persistent-storage", use_persistent_storage)
|
||||
handlePersistantSetting (use_persistent_storage)
|
||||
elseif setting == "policy.bluetooth.media-role.use-headset-profile" then
|
||||
use_headset_profile = Settings.parse_boolean_safe
|
||||
("policy.bluetooth.media-role.use-headset-profile", use_headset_profile)
|
||||
elseif setting == "policy.bluetooth.media-role.applications" then
|
||||
local new_apps_setting = Settings.parse_array_safe
|
||||
("policy.bluetooth.media-role.applications")
|
||||
if #new_apps_setting > 0 then
|
||||
apps_setting = new_apps_setting
|
||||
loadAppNames (apps_setting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Settings.subscribe ("policy.bluetooth*", settingsChangedCallback)
|
||||
|
||||
handlePersistantSetting (use_persistent_storage)
|
||||
|
||||
local applications = {}
|
||||
local profile_restore_timeout_msec = 2000
|
||||
|
|
@ -38,25 +78,18 @@ local INVALID = -1
|
|||
local timeout_source = nil
|
||||
local restore_timeout_source = nil
|
||||
|
||||
local state = use_persistent_storage and State ("policy-bluetooth") or nil
|
||||
local headset_profiles = state and state:load () or {}
|
||||
local last_profiles = {}
|
||||
|
||||
local active_streams = {}
|
||||
local previous_streams = {}
|
||||
|
||||
local apps_setting =
|
||||
Settings.parse_array_safe ("bt-policy-media-role.applications")
|
||||
for i = 1, #apps_setting do
|
||||
applications [apps_setting [i]] = true
|
||||
function loadAppNames (appNames)
|
||||
for i = 1, #appNames do
|
||||
applications [appNames [i]] = true
|
||||
end
|
||||
end
|
||||
|
||||
metadata_om = ObjectManager {
|
||||
Interest {
|
||||
type = "metadata",
|
||||
Constraint { "metadata.name", "=", "default" },
|
||||
}
|
||||
}
|
||||
loadAppNames (apps_setting)
|
||||
|
||||
devices_om = ObjectManager {
|
||||
Interest {
|
||||
|
|
@ -74,36 +107,10 @@ streams_om = ObjectManager {
|
|||
}
|
||||
}
|
||||
|
||||
local function parseParam (param_to_parse, id)
|
||||
local param = param_to_parse:parse ()
|
||||
if param.pod_type == "Object" and param.object_id == id then
|
||||
return param.properties
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function storeAfterTimeout ()
|
||||
if not use_persistent_storage then
|
||||
return
|
||||
end
|
||||
|
||||
if timeout_source then
|
||||
timeout_source:destroy ()
|
||||
end
|
||||
timeout_source = Core.timeout_add (1000, function ()
|
||||
local saved, err = state:save (headset_profiles)
|
||||
if not saved then
|
||||
Log.warning (err)
|
||||
end
|
||||
timeout_source = nil
|
||||
end)
|
||||
end
|
||||
|
||||
local function saveHeadsetProfile (device, profile_name)
|
||||
local key = "saved-headset-profile:" .. device.properties ["device.name"]
|
||||
headset_profiles [key] = profile_name
|
||||
storeAfterTimeout ()
|
||||
cutils.storeAfterTimeout (state, headset_profiles)
|
||||
end
|
||||
|
||||
local function getSavedHeadsetProfile (device)
|
||||
|
|
@ -131,14 +138,14 @@ local function isBluez5AudioSink (sink_name)
|
|||
end
|
||||
|
||||
local function isBluez5DefaultAudioSink ()
|
||||
local metadata = metadata_om:lookup ()
|
||||
local metadata = cutils.default_metadata_om:lookup ()
|
||||
local default_audio_sink = metadata:find (0, "default.audio.sink")
|
||||
return isBluez5AudioSink (default_audio_sink)
|
||||
end
|
||||
|
||||
local function findProfile (device, index, name)
|
||||
for p in device:iterate_params ("EnumProfile") do
|
||||
local profile = parseParam (p, "EnumProfile")
|
||||
local profile = cutils.parseParam (p, "EnumProfile")
|
||||
if not profile then
|
||||
goto skip_enum_profile
|
||||
end
|
||||
|
|
@ -158,7 +165,7 @@ end
|
|||
|
||||
local function getCurrentProfile (device)
|
||||
for p in device:iterate_params ("Profile") do
|
||||
local profile = parseParam (p, "Profile")
|
||||
local profile = cutils.parseParam (p, "Profile")
|
||||
if profile then
|
||||
return profile.name
|
||||
end
|
||||
|
|
@ -173,7 +180,7 @@ local function highestPrioProfileWithInputRoute (device)
|
|||
local profile_name = nil
|
||||
|
||||
for p in device:iterate_params ("EnumRoute") do
|
||||
local route = parseParam (p, "EnumRoute")
|
||||
local route = cutils.parseParam (p, "EnumRoute")
|
||||
-- Parse pod
|
||||
if not route then
|
||||
goto skip_enum_route
|
||||
|
|
@ -207,7 +214,7 @@ end
|
|||
|
||||
local function hasProfileInputRoute (device, profile_index)
|
||||
for p in device:iterate_params ("EnumRoute") do
|
||||
local route = parseParam (p, "EnumRoute")
|
||||
local route = cutils.parseParam (p, "EnumRoute")
|
||||
if route and route.direction == "Input" and route.profiles then
|
||||
for _, v in pairs (route.profiles) do
|
||||
if v == profile_index then
|
||||
|
|
@ -448,12 +455,11 @@ SimpleEventHook {
|
|||
},
|
||||
execute = function (event)
|
||||
if (use_headset_profile) then
|
||||
-- If bluez sink is set as default, rescan for active input streams
|
||||
handleAllStreams ()
|
||||
-- If bluez sink is set as default, rescan for active input streams
|
||||
handleAllStreams ()
|
||||
end
|
||||
end
|
||||
}:register ()
|
||||
|
||||
metadata_om:activate ()
|
||||
devices_om:activate ()
|
||||
streams_om:activate ()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
-- Settings file: device.conf
|
||||
|
||||
local cutils = require ("common-utils")
|
||||
|
||||
local self = {}
|
||||
self.active_profiles = {}
|
||||
self.default_profile_plugin = Plugin.find ("default-profile")
|
||||
|
|
@ -27,16 +29,6 @@ function isProfilePersistent (device_props, profile_name)
|
|||
return false
|
||||
end
|
||||
|
||||
|
||||
function parseParam (param, id)
|
||||
local parsed = param:parse ()
|
||||
if parsed.pod_type == "Object" and parsed.object_id == id then
|
||||
return parsed.properties
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function setDeviceProfile (device, dev_id, dev_name, profile)
|
||||
if self.active_profiles [dev_id] and
|
||||
self.active_profiles [dev_id].index == profile.index then
|
||||
|
|
@ -63,7 +55,7 @@ function findDefaultProfile (device)
|
|||
end
|
||||
|
||||
for p in device:iterate_params ("EnumProfile") do
|
||||
local profile = parseParam (p, "EnumProfile")
|
||||
local profile = cutils.parseParam (p, "EnumProfile")
|
||||
if profile.name == def_name then
|
||||
return profile
|
||||
end
|
||||
|
|
@ -78,7 +70,7 @@ function findBestProfile (device)
|
|||
local unk_profile = nil
|
||||
|
||||
for p in device:iterate_params ("EnumProfile") do
|
||||
profile = parseParam (p, "EnumProfile")
|
||||
profile = cutils.parseParam (p, "EnumProfile")
|
||||
if profile and profile.name ~= "pro-audio" then
|
||||
if profile.name == "off" then
|
||||
off_profile = profile
|
||||
|
|
@ -150,10 +142,8 @@ function handleProfiles (device, new_device)
|
|||
end
|
||||
end
|
||||
|
||||
function onDeviceParamsChanged (device, param_name)
|
||||
if param_name == "EnumProfile" then
|
||||
handleProfiles (device, false)
|
||||
end
|
||||
function onDeviceParamsChanged (device)
|
||||
handleProfiles (device, false)
|
||||
end
|
||||
|
||||
SimpleEventHook {
|
||||
|
|
@ -179,14 +169,11 @@ SimpleEventHook {
|
|||
EventInterest {
|
||||
Constraint { "event.type", "=", "params-changed" },
|
||||
Constraint { "event.subject.type", "=", "device" },
|
||||
Constraint { "event.subject.param-id", "=", "EnumProfile" },
|
||||
},
|
||||
},
|
||||
execute = function (event)
|
||||
local device = event:get_subject ()
|
||||
local props = event:get_properties()
|
||||
local param_name = props ["event.subject.param-id"]
|
||||
|
||||
onDeviceParamsChanged (device, param_name)
|
||||
onDeviceParamsChanged (event:get_subject ())
|
||||
end
|
||||
}:register()
|
||||
|
||||
|
|
|
|||
|
|
@ -12,87 +12,58 @@
|
|||
-- device profiles. It selects and enables the routes(Route here is a path on
|
||||
-- soundcard/Pipewire Device(PipeWire:Interface:Device), for example: speaker,
|
||||
-- mic, headset with in a soundcard) needed for a given profile. It also caches
|
||||
-- the route properties(Volume, Mute, channelVolumes, channelMap etc) and
|
||||
-- restores them when the route appears afresh. The cached properties are
|
||||
-- the route specific properties(Volume, Mute, channelVolumes, channelMap etc)
|
||||
-- and restores them when the route appears afresh. The cached properties are
|
||||
-- remembered across reboots if persistancy(use_persistent_storage) is enabled.
|
||||
|
||||
-- settings file: device.conf
|
||||
|
||||
local cutils = require ("common-utils")
|
||||
|
||||
local use_persistent_storage =
|
||||
Settings.parse_boolean_safe ("device.use-persistent-storage", true)
|
||||
local default_volume =
|
||||
Settings.parse_float_safe ("device.default-volume", 0.4^3)
|
||||
local default_input_volume =
|
||||
Settings.parse_float_safe ("default-input-volume", 1.0)
|
||||
Settings.parse_float_safe ("device.default-input-volume", 1.0)
|
||||
|
||||
-- table of device info
|
||||
dev_infos = {}
|
||||
|
||||
-- the state storage
|
||||
state = use_persistent_storage and State ("default-routes") or nil
|
||||
state_table = state and state:load () or {}
|
||||
state = nil
|
||||
state_table = nil
|
||||
|
||||
-- simple serializer {"foo", "bar"} -> "foo;bar;"
|
||||
function serializeArray (a)
|
||||
local str = ""
|
||||
for _, v in ipairs (a) do
|
||||
str = str .. tostring (v):gsub (";", "\\;") .. ";"
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
-- simple deserializer "foo;bar;" -> {"foo", "bar"}
|
||||
function parseArray (str, convert_value)
|
||||
local array = {}
|
||||
local val = ""
|
||||
local escaped = false
|
||||
for i = 1, #str do
|
||||
local c = str:sub (i,i)
|
||||
if c == '\\' then
|
||||
escaped = true
|
||||
elseif c == ';' and not escaped then
|
||||
val = convert_value and convert_value (val) or val
|
||||
table.insert (array, val)
|
||||
val = ""
|
||||
else
|
||||
val = val .. tostring (c)
|
||||
escaped = false
|
||||
end
|
||||
end
|
||||
return array
|
||||
end
|
||||
|
||||
function arrayContains (a, value)
|
||||
for _, v in ipairs (a) do
|
||||
if v == value then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function parseParam (param, id)
|
||||
local route = param:parse ()
|
||||
if route.pod_type == "Object" and route.object_id == id then
|
||||
return route.properties
|
||||
function handlePersistantSetting (enable)
|
||||
if enable and state == nil then
|
||||
-- the state storage
|
||||
state = use_persistent_storage and State ("default-routes") or nil
|
||||
state_table = state and state:load () or {}
|
||||
else
|
||||
return nil
|
||||
state = nil
|
||||
state_table = nil
|
||||
end
|
||||
end
|
||||
|
||||
function storeAfterTimeout ()
|
||||
if timeout_source then
|
||||
timeout_source:destroy ()
|
||||
local function settingsChangedCallback (_, setting, _)
|
||||
local value = Settings.get (setting):parse ()
|
||||
|
||||
if setting == "device.use-persistent-storage" then
|
||||
use_persistent_storage = Settings.parse_boolean_safe
|
||||
("device.use-persistent-storage", use_persistent_storage)
|
||||
handlePersistantSetting (use_persistent_storage)
|
||||
elseif setting == "device.default-volume" then
|
||||
default_volume = Settings.parse_float_safe ("device.default-volume",
|
||||
default_volume)
|
||||
elseif setting == "device.default-input-volume" then
|
||||
default_input_volume = Settings.parse_float_safe
|
||||
("device.default-input-volume", default_input_volume)
|
||||
end
|
||||
timeout_source = Core.timeout_add (1000, function ()
|
||||
local saved, err = state:save (state_table)
|
||||
if not saved then
|
||||
Log.warning (err)
|
||||
end
|
||||
timeout_source = nil
|
||||
end)
|
||||
end
|
||||
|
||||
Settings.subscribe ("device*", settingsChangedCallback)
|
||||
|
||||
handlePersistantSetting (use_persistent_storage)
|
||||
|
||||
function saveProfile (dev_info, profile_name)
|
||||
if not use_persistent_storage then
|
||||
return
|
||||
|
|
@ -107,8 +78,8 @@ function saveProfile (dev_info, profile_name)
|
|||
|
||||
if #routes > 0 then
|
||||
local key = dev_info.name .. ":profile:" .. profile_name
|
||||
state_table [key] = serializeArray (routes)
|
||||
storeAfterTimeout ()
|
||||
state_table [key] = cutils.serializeArray (routes)
|
||||
cutils.storeAfterTimeout (state, state_table)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -127,15 +98,15 @@ function saveRouteProps (dev_info, route)
|
|||
state_table [key_base .. "mute"] =
|
||||
props.mute and tostring (props.mute) or nil
|
||||
state_table [key_base .. "channelVolumes"] =
|
||||
props.channelVolumes and serializeArray (props.channelVolumes) or nil
|
||||
props.channelVolumes and cutils.serializeArray (props.channelVolumes) or nil
|
||||
state_table [key_base .. "channelMap"] =
|
||||
props.channelMap and serializeArray (props.channelMap) or nil
|
||||
props.channelMap and cutils.serializeArray (props.channelMap) or nil
|
||||
state_table [key_base .. "latencyOffsetNsec"] =
|
||||
props.latencyOffsetNsec and tostring (props.latencyOffsetNsec) or nil
|
||||
state_table [key_base .. "iec958Codecs"] =
|
||||
props.iec958Codecs and serializeArray (props.iec958Codecs) or nil
|
||||
props.iec958Codecs and cutils.serializeArray (props.iec958Codecs) or nil
|
||||
|
||||
storeAfterTimeout ()
|
||||
cutils.storeAfterTimeout (state, state_table)
|
||||
end
|
||||
|
||||
function restoreRoute (device, dev_info, device_id, route)
|
||||
|
|
@ -164,16 +135,17 @@ function restoreRoute (device, dev_info, device_id, route)
|
|||
props.mute = str and (str == "true") or false
|
||||
|
||||
local str = state_table [key_base .. "channelVolumes"]
|
||||
props.channelVolumes = str and parseArray (str, tonumber) or props.channelVolumes
|
||||
props.channelVolumes =
|
||||
str and cutils.parseArray (str, tonumber) or props.channelVolumes
|
||||
|
||||
local str = state_table [key_base .. "channelMap"]
|
||||
props.channelMap = str and parseArray (str) or props.channelMap
|
||||
props.channelMap = str and cutils.parseArray (str) or props.channelMap
|
||||
|
||||
local str = state_table [key_base .. "latencyOffsetNsec"]
|
||||
props.latencyOffsetNsec = str and math.tointeger (str) or props.latencyOffsetNsec
|
||||
|
||||
local str = state_table [key_base .. "iec958Codecs"]
|
||||
props.iec958Codecs = str and parseArray (str) or props.iec958Codecs
|
||||
props.iec958Codecs = str and cutils.parseArray (str) or props.iec958Codecs
|
||||
end
|
||||
|
||||
-- convert arrays to Spa Pod
|
||||
|
|
@ -264,16 +236,16 @@ end
|
|||
function getStoredProfileRoutes (dev_name, profile_name)
|
||||
local key = dev_name .. ":profile:" .. profile_name
|
||||
local str = state_table [key]
|
||||
return str and parseArray (str) or {}
|
||||
return str and cutils.parseArray (str) or {}
|
||||
end
|
||||
|
||||
-- find a route that was previously stored for a device_id
|
||||
-- spr needs to be the array returned from getStoredProfileRoutes()
|
||||
function findSavedRoute(dev_info, device_id, spr)
|
||||
for idx, ri in pairs(dev_info.route_infos) do
|
||||
if arrayContains(ri.devices, device_id) and
|
||||
(ri.profiles == nil or arrayContains(ri.profiles, dev_info.active_profile)) and
|
||||
arrayContains(spr, ri.name) then
|
||||
if cutils.arrayContains (ri.devices, device_id) and
|
||||
(ri.profiles == nil or cutils.arrayContains (ri.profiles, dev_info.active_profile)) and
|
||||
cutils.arrayContains (spr, ri.name) then
|
||||
return ri
|
||||
end
|
||||
end
|
||||
|
|
@ -285,8 +257,8 @@ function findBestRoute (dev_info, device_id)
|
|||
local best_avail = nil
|
||||
local best_unk = nil
|
||||
for idx, ri in pairs(dev_info.route_infos) do
|
||||
if arrayContains(ri.devices, device_id) and
|
||||
(ri.profiles == nil or arrayContains(ri.profiles, dev_info.active_profile)) then
|
||||
if cutils.arrayContains (ri.devices, device_id) and
|
||||
(ri.profiles == nil or cutils.arrayContains (ri.profiles, dev_info.active_profile)) then
|
||||
if ri.available == "yes" or ri.available == "unknown" then
|
||||
if ri.direction == "Output" and ri.available ~= ri.prev_available then
|
||||
best_avail = ri
|
||||
|
|
@ -395,13 +367,13 @@ function handleDevice (device)
|
|||
|
||||
-- get current profile
|
||||
for p in device:iterate_params ("Profile") do
|
||||
profile = parseParam (p, "Profile")
|
||||
profile = cutils.parseParam (p, "Profile")
|
||||
end
|
||||
|
||||
-- look at all the routes and update/reset cached information
|
||||
for p in device:iterate_params ("EnumRoute") do
|
||||
-- parse pod
|
||||
local route = parseParam (p, "EnumRoute")
|
||||
local route = cutils.parseParam (p, "EnumRoute")
|
||||
if not route then
|
||||
goto skip_enum_route
|
||||
end
|
||||
|
|
@ -415,7 +387,7 @@ function handleDevice (device)
|
|||
Log.info (device, "route " .. route.name .. " available changed " ..
|
||||
route_info.available .. " -> " .. route.available)
|
||||
route_info.available = route.available
|
||||
if profile and arrayContains (route.profiles, profile.index) then
|
||||
if profile and cutils.arrayContains (route.profiles, profile.index) then
|
||||
avail_routes_changed = true
|
||||
end
|
||||
end
|
||||
|
|
@ -436,7 +408,7 @@ function handleDevice (device)
|
|||
|
||||
-- check for changes in the active routes
|
||||
for p in device:iterate_params ("Route") do
|
||||
local route = parseParam (p, "Route")
|
||||
local route = cutils.parseParam (p, "Route")
|
||||
if not route then
|
||||
goto skip_route
|
||||
end
|
||||
|
|
@ -539,9 +511,16 @@ SimpleEventHook {
|
|||
EventInterest {
|
||||
Constraint { "event.type", "=", "params-changed" },
|
||||
Constraint { "event.subject.type", "=", "device" },
|
||||
Constraint { "event.subject.param-id", "=", "Route" },
|
||||
},
|
||||
EventInterest {
|
||||
Constraint { "event.type", "=", "params-changed" },
|
||||
Constraint { "event.subject.type", "=", "device" },
|
||||
Constraint { "event.subject.param-id", "=", "EnumRoute" },
|
||||
},
|
||||
},
|
||||
execute = function (event)
|
||||
handleDevice (event:get_subject())
|
||||
local props = event:get_properties ()
|
||||
handleDevice (event:get_subject ())
|
||||
end
|
||||
}:register()
|
||||
|
|
|
|||
|
|
@ -29,19 +29,6 @@ default_channel_volume = Settings.parse_float_safe (
|
|||
state = State ("restore-stream")
|
||||
state_table = state:load ()
|
||||
|
||||
function storeAfterTimeout ()
|
||||
if timeout_source then
|
||||
timeout_source:destroy ()
|
||||
end
|
||||
timeout_source = Core.timeout_add (1000, function ()
|
||||
local saved, err = state:save (state_table)
|
||||
if not saved then
|
||||
Log.warning (err)
|
||||
end
|
||||
timeout_source = nil
|
||||
end)
|
||||
end
|
||||
|
||||
function formKeyBase (properties)
|
||||
local keys = {
|
||||
"media.role",
|
||||
|
|
@ -116,7 +103,7 @@ function saveTarget (subject, target_key, type, value)
|
|||
Log.info (node, "saving stream target for " ..
|
||||
tostring (stream_props ["node.name"]) .. " -> " .. tostring (target_name))
|
||||
|
||||
storeAfterTimeout ()
|
||||
cutils.storeAfterTimeout (state, state_table)
|
||||
end
|
||||
|
||||
function restoreTarget(node, target_name)
|
||||
|
|
@ -260,7 +247,7 @@ function saveStream (node)
|
|||
::skip_prop::
|
||||
end
|
||||
|
||||
storeAfterTimeout ()
|
||||
cutils.storeAfterTimeout (state, state_table)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -445,7 +432,7 @@ function handleRouteSettings (subject, key, type, value)
|
|||
state_table [key_base .. ":channelVolumes"] = cutils.serializeArray (vparsed.volumes)
|
||||
end
|
||||
|
||||
storeAfterTimeout ()
|
||||
cutils.storeAfterTimeout (state, state_table)
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -561,7 +548,7 @@ local function settingsChangedCallback (_, setting, _)
|
|||
end
|
||||
end
|
||||
|
||||
local settings_sub_id = Settings.subscribe ("stream*", settingsChangedCallback)
|
||||
Settings.subscribe ("stream*", settingsChangedCallback)
|
||||
|
||||
streams_om = ObjectManager {
|
||||
-- match stream nodes
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue