如何用LGI从D-Bus读取属性?信号回调call_sync阻塞问题
问题:LGI订阅DBus信号后调用
call_sync卡住无法获取PlaybackStatus 我尝试使用lgi订阅DBus信号并读取属性,代码如下:
local lgi = require("lgi") local Gio, GLib = lgi.Gio, lgi.GLib local name = "org.freedesktop.DBus" local path = "/org/freedesktop/DBus" local iface = "org.freedesktop.DBus" Gio.DBusProxy.new_for_bus( Gio.BusType.SESSION, Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES, nil, name, path, iface, nil, function(bus_proxy) local conn = bus_proxy:get_connection() local sub_id = conn:signal_subscribe( nil, "org.freedesktop.DBus.Properties", "PropertiesChanged", "/org/mpris/MediaPlayer2", nil, Gio.DBusSignalFlags.NONE, function() local value = GLib.Variant.new( "(ss)", { "org.mpris.MediaPlayer2.Player", "PlaybackStatus" } ) local playback_status = bus_proxy:call_sync( "org.freedesktop.DBus.Properties.Get", value, Gio.DBusCallFlags.NONE, -1, nil ) print(playback_status) end) end, nil )
我能确认信号已正确订阅,每次在Youtube上暂停或播放视频时回调都会触发,但bus_proxy:call_sync会卡住,始终无法返回PlaybackStatus的值。请问我哪里操作有误?
问题原因及解决方法
错误根源
你创建的bus_proxy是连接到org.freedesktop.DBus服务的代理,但org.freedesktop.DBus.Properties.Get方法需要调用MPRIS播放器服务(比如Chrome对应的org.mpris.MediaPlayer2.chrome),而不是DBus自身服务。用当前的bus_proxy发起请求,相当于给DBus服务发了它无法处理的MPRIS属性查询,导致调用卡住。
解决步骤
- 复用DBus连接对象发起调用:在信号回调里,使用
conn:call_sync代替bus_proxy:call_sync,并指定正确的目标服务名、对象路径和接口。 - 从信号参数获取服务名:信号回调的第二个参数
sender就是发送信号的MPRIS服务名,直接用它指定目标服务,兼容所有MPRIS播放器,无需硬编码。 - 优先从信号参数读取属性:
PropertiesChanged信号本身会携带变化的属性,直接解析参数就能获取值,无需额外发起DBus调用,效率更高。
修正后的代码
local lgi = require("lgi") local Gio, GLib = lgi.Gio, lgi.GLib local name = "org.freedesktop.DBus" local path = "/org/freedesktop/DBus" local iface = "org.freedesktop.DBus" Gio.DBusProxy.new_for_bus( Gio.BusType.SESSION, Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES, nil, name, path, iface, nil, function(bus_proxy) local conn = bus_proxy:get_connection() local sub_id = conn:signal_subscribe( nil, "org.freedesktop.DBus.Properties", "PropertiesChanged", "/org/mpris/MediaPlayer2", nil, Gio.DBusSignalFlags.NONE, function(conn, sender, object_path, interface_name, signal_name, parameters) -- 优先从信号参数读取变化的PlaybackStatus local changed_props = parameters:get_child_value(1) local playback_status_variant = changed_props:lookup_value("PlaybackStatus", nil) if playback_status_variant then print("PlaybackStatus:", playback_status_variant.value) return end -- 信号未携带时,主动查询目标服务 local value = GLib.Variant.new( "(ss)", { "org.mpris.MediaPlayer2.Player", "PlaybackStatus" } ) local playback_status = conn:call_sync( sender, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get", value, GLib.VariantType.new("(v)"), Gio.DBusCallFlags.NONE, -1, nil ) -- 解析返回的Variant值 local status = playback_status:get_child_value(0).value print("PlaybackStatus (查询):", status) end) end, nil )
内容的提问来源于stack exchange,提问作者arielnmz
相关产品推荐
相关产品推荐

