lgi-devs / lgi

Dynamic Lua binding to GObject libraries using GObject-Introspection
MIT License
436 stars 69 forks source link

How to connect signal on derived class of GstBin? #293

Open fastcoding opened 2 years ago

fastcoding commented 2 years ago

For example,

local Gst=lgi.Gst
local bin=Gst.parse_bin_from_description('rtspsrc location="rtsp://...."  name=mysrc ! rtph264depay ', true)
local rtspsrc=bin:get_by_name('mysrc')
function rtspsrc:on_on_sdp(sdp,ud)
    print('got sdp:',sdp)
end

when connecting to 'on-sdp' signal on a GstRtspSrc object, the above codes would fail with error message:

Gst.Bin: no `on_on_sdp'

It seems signals are loaded from GI typelib rather than through gobject runtime query. Maybe the way I'm using signals for such case is wrong?

pavouk commented 2 years ago

Most probably lgi does not have loaded GI typelib for GstRtspSrc object, so it treats it as its parent, GstBin. Try loading GstRtspSrc first using something like local GstRtsp = lgi.GstRtsp.

fastcoding commented 2 years ago

Thanks for reply. But unfortunately GstRtspSrc namespace doesn't exist. I just checked the meson.build file in GstRtspSrc (in gst-plugins-good), it doesn't include a g-ir-scanner command in the build like other Gst components do. I don't know whether it's intentional or not. That means the only way is to manually create typelib or cannot use lgi for this case.

I tried directly calling GObject.signal_connect_closure_by_id. It can connect signal successfully, but fail when closure gets invoked.

Error raised while calling 'lgi.cbk (function: 0x0100e72ea0): GObject': attempt to index 
a nil value

Is it possible to create a user defined GICallableInfo to make the closure callback marshalling work?

pavouk commented 2 years ago

Interesting, this page https://packages.debian.org/sid/i386/gir1.2-gst-plugins-base-1.0/filelist indicates that GstRtsp should exist. Note that typelib is GstRtsp, not GstRtspSrc. I don't remember how to connect signal manually, sorry.

fastcoding commented 2 years ago

yes, GstRtsp and GstRtspSrc are different components. The latter can be directly used in pipeline and what I'd like to use lgi to control. I've mentioned using GObject.signal_connect_closure_by_id to manually connect to 'on-sdp' signal, the code was basically copied from lgi/overides/GObject-Object.lua, like this:

local signal_lookup = GObject.signal_lookup
local Closure=GObject.Closure
local signal_connect_closure_by_id = GObject.signal_connect_closure_by_id
-- Connects signal to specified object instance.
local function connect_signal(obj, name, closure, detail, after)
   assert(obj._gtype)
   local id=signal_lookup(name, obj._gtype)
   assert(id)
   print('id=',id)
   return signal_connect_closure_by_id(
      obj,id ,
      detail and quark_from_string(detail) or 0,
      closure, after or false)
end
local clo=Closure( function(sdp,ud)
    print('rtsp got sdp:',sdp)
    return 1
end)
assert(clo)
connect_signal(rtspsrc,'on-sdp',clo)

The issue for this work-around is it will throw error when receiving callback. I guess it's due to lack of the GICallbackInfo interface, lgi doesn't know how to unpack the parameters. Thanks anyway, I will look for other ways around this.

fastcoding commented 2 years ago

The above problem was eventually solved by me. Here is one line patch:

--- a/lgi/override/GObject-Closure.lua
+++ b/lgi/override/GObject-Closure.lua
@@ -282,7 +282,7 @@ function Closure:_new(target, callback_info)
         -- Create marshaller based only on Value types.
         function marshaller(closure, retval, params)
            local args = {}
-           for i, val in ipairs(params) do args[i] = val.value end
+           for i, val in ipairs(params) do args[i] = val end
            local ret = target(unpack(args, 1, #params))
            if retval then retval.value = ret end
         end

In my case, whenever receiving 'on-sdp' callback, one of the params (userdata) passed to the marshaller is nil,

    args[i]=nil.value

and thus results in lgi.callable throw error.