After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 792601 - Message bus lockup if getting pipeline state
Message bus lockup if getting pipeline state
Status: RESOLVED NOTABUG
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
git master
Other Linux
: Normal normal
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2018-01-17 12:07 UTC by Florent Thiéry
Modified: 2018-01-17 18:05 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
reproduction test (python) (761 bytes, text/x-python)
2018-01-17 12:07 UTC, Florent Thiéry
Details

Description Florent Thiéry 2018-01-17 12:07:35 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.
Comment 1 Tim-Philipp Müller 2018-01-17 12:13:53 UTC
> 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.
Comment 2 Florent Thiéry 2018-01-17 13:24:17 UTC
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.
Comment 3 Florent Thiéry 2018-01-17 13:32:38 UTC
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 ?
Comment 4 Tim-Philipp Müller 2018-01-17 15:51:34 UTC
perhaps you meant ASYNC_DONE?

The safe way to avoid blocking is to pass a timeout of 0 to get_state().
Comment 5 Florent Thiéry 2018-01-17 17:37:41 UTC
(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.
Comment 6 Tim-Philipp Müller 2018-01-17 18:05:48 UTC
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 :)