mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-16 08:14:03 -04:00
* bluetooth: identify codecs from the profile description PipeWire describes profiles in the daemon's locale and only names the codec in that description for the bare profile (LHDC settles on "a2dp-sink"), so the old English "codec %s" match dropped LHDC profiles on non-English systems. Parsing the translated shape instead only moves the coupling to word order and punctuation. Emit the profile index and raw description from the lua script and let the UI name the codec by matching the untranslated literal from one codec table. Switch by index, falling back to the profile name or codec literal, so no translated text is parsed. Also teach the BlueZ fallback the Savitech ids (LHDC v5 and v3). Test: quickshell/tests/bluez-codec.test.mjs * bluetooth: show unknown codec without masking bluez * bluetooth: ignore stale codec query results
144 lines
3.5 KiB
Lua
Executable File
144 lines
3.5 KiB
Lua
Executable File
#!/usr/bin/wpexec
|
|
cutils = require("common-utils")
|
|
|
|
local args = (...):parse()
|
|
local mode = args.mode or "list"
|
|
local dev_name = args.device or ""
|
|
local target = args.target or ""
|
|
|
|
local function fail(msg)
|
|
print("ERROR: " .. msg)
|
|
Core.quit()
|
|
end
|
|
|
|
if dev_name == "" then
|
|
fail("missing device")
|
|
return
|
|
end
|
|
|
|
local om = ObjectManager {
|
|
Interest {
|
|
type = "device",
|
|
Constraint { "media.class", "=", "Audio/Device", type = "pw-global" },
|
|
}
|
|
}
|
|
|
|
local handled = false
|
|
|
|
local function profile_available(profile)
|
|
return profile and profile.available ~= "no"
|
|
end
|
|
|
|
local function handle_device(device)
|
|
if handled then
|
|
return
|
|
end
|
|
local name = device.properties["device.name"] or ""
|
|
if name ~= dev_name then
|
|
return
|
|
end
|
|
handled = true
|
|
|
|
if mode == "list" then
|
|
local active_index = nil
|
|
for p in device:iterate_params("Profile") do
|
|
local active = cutils.parseParam(p, "Profile")
|
|
if active then
|
|
active_index = active.index
|
|
end
|
|
end
|
|
|
|
for p in device:iterate_params("EnumProfile") do
|
|
local profile = cutils.parseParam(p, "EnumProfile")
|
|
if profile_available(profile) then
|
|
local current = (active_index ~= nil and profile.index == active_index) and "1" or "0"
|
|
print(string.format("CODEC\t%s\t%s\t%s\t%s",
|
|
tostring(profile.index), profile.name or "", profile.description or "", current))
|
|
end
|
|
end
|
|
Core.quit()
|
|
return
|
|
end
|
|
|
|
if mode == "set" then
|
|
local target_index = tonumber(args.index)
|
|
local target_codec = tostring(args.codec or "")
|
|
if target == "" and target_index == nil and target_codec == "" then
|
|
fail("missing target")
|
|
return
|
|
end
|
|
|
|
-- A stale index must not outrank the profile the UI picked: try the exact
|
|
-- profile name first, then the codec literal, then the index.
|
|
local target_lower = tostring(target):lower()
|
|
local match = nil
|
|
local best_rank = 4
|
|
for p in device:iterate_params("EnumProfile") do
|
|
local profile = cutils.parseParam(p, "EnumProfile")
|
|
if profile_available(profile) then
|
|
local pname = profile.name or ""
|
|
local description = tostring(profile.description or ""):lower()
|
|
local rank = 4
|
|
if target ~= "" and (pname == target or pname:lower() == target_lower) then
|
|
rank = 1
|
|
elseif target_codec ~= "" and description:find(target_codec:lower(), 1, true) then
|
|
rank = 2
|
|
elseif target_index ~= nil and tonumber(profile.index) == target_index then
|
|
rank = 3
|
|
end
|
|
if rank < best_rank then
|
|
best_rank = rank
|
|
match = profile
|
|
if rank == 1 then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if not match then
|
|
fail("profile not found: " .. (target ~= "" and target or target_codec))
|
|
return
|
|
end
|
|
|
|
local param = Pod.Object {
|
|
"Spa:Pod:Object:Param:Profile", "Profile",
|
|
index = tonumber(match.index),
|
|
save = true,
|
|
}
|
|
device:set_param("Profile", param)
|
|
Core.sync(function()
|
|
print("OK\t" .. (match.name or target))
|
|
Core.quit()
|
|
end)
|
|
return
|
|
end
|
|
|
|
fail("unknown mode " .. mode)
|
|
end
|
|
|
|
om:connect("object-added", function(_, device)
|
|
handle_device(device)
|
|
end)
|
|
|
|
om:connect("installed", function()
|
|
if handled then
|
|
return
|
|
end
|
|
for device in om:iterate() do
|
|
handle_device(device)
|
|
if handled then
|
|
return
|
|
end
|
|
end
|
|
fail("device not found: " .. dev_name)
|
|
end)
|
|
|
|
om:activate()
|
|
Core.timeout_add(3000, function()
|
|
if not handled then
|
|
fail("timed out waiting for device " .. dev_name)
|
|
end
|
|
return false
|
|
end)
|