GNOME Bugzilla – Bug 792601
Message bus lockup if getting pipeline state
Last modified: 2018-01-17 18:05:48 UTC
Created attachment 366930 [details] reproduction test (python) In advance, i'm sorry if this ticket title is wrong, and if it is in the wrong project (-core or -good). I was initially trying to trigger an action upon receiving GstUDPSrcTimeout messages from the message bus. pd = "udpsrc timeout=2000000000 ! fakesink" My application was never receiving these events, and i managed to reproduce it. The app locks up when getting the state of the pipeline (note that udpsrc is intentionally not getting any data). import gi gi.require_version("Gst", "1.0") from gi.repository import GObject, Gst, GLib Gst.init(None) pd = "udpsrc timeout=2000000000 ! fakesink" def on_message(bus, message): t = message.type if t == Gst.MessageType.ELEMENT: struct = message.get_structure() sname = struct.get_name() print(sname) if sname == "GstUDPSrcTimeout": print('UDP Timeout !!') p = Gst.parse_launch(pd) bus = p.get_bus() bus.add_signal_watch() bus.connect("message", on_message) ml = GObject.MainLoop() GObject.idle_add(p.set_state, Gst.State.PLAYING) # Uncomment this to freeze the bus (udptimeout messages not received) GObject.idle_add(p.get_state, Gst.CLOCK_TIME_NONE) ml.run() If i comment the line that gets the state of the pipeline, the udp timeout messages are received. Otherwise, nothing happens and the software becomes unresponsive.
> GObject.idle_add(p.set_state, Gst.State.PLAYING) > # Uncomment this to freeze the bus (udptimeout messages not received) > GObject.idle_add(p.get_state, Gst.CLOCK_TIME_NONE) These two look very dubious to me. get_state takes more parameters and also both functions return a GstStateChangeReturn and not a boolean. I would recommend you write a test case in C first.
Indeed the set_state to playing returns GST_STATE_CHANGE_ASYNC, in which case the get_state documentation says: "For elements that did not return GST_STATE_CHANGE_ASYNC, this function returns the current and pending state immediately." (https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-state) This explains why get_state is blocking the pipeline, until Gst.MessageType.STREAM_START is received, sorry i was not aware of this. Thanks for taking a look.
Actually, if i get_state on the pipeline when getting STREAM_START on the bus, get_state is still blocking. What is the safe way to avoid getting a blocking get_state ?
perhaps you meant ASYNC_DONE? The safe way to avoid blocking is to pass a timeout of 0 to get_state().
(In reply to Tim-Philipp Müller from comment #4) > perhaps you meant ASYNC_DONE? Many thanks, is that safe to assume that ASYNC_DONE will always be happening and can be used as criteria for asserting whether the pipeline is PLAYING (without polling the state ? > The safe way to avoid blocking is to pass a timeout of 0 to get_state(). Many thanks, that did it.
ASYNC_DONE indicates that the pipeline is now prerolled. If you set the pipeline to PLAYING state originally, it will either just have gone to PLAYING or is about to go to PLAYING very soon now (you will have picked up the message from your main thread so don't know what happened in the streaming threads in the time since it was posted). If you want push-based notification for the pipeline state, use STATE_CHANGED messages (with msg->src == pipeline). If there are more questions, perhaps we can move this to irc or the mailing list :)