GNOME Bugzilla – Bug 731121
alsasink: Race condition causes alsasink to use invalid caps when a pipeline fails to start
Last modified: 2014-06-03 14:21:14 UTC
Writing out my findings to remember, I will continue debugging this tomorrow if not preempted. It started as a simple one off assert in gst_value_intersect: (gst-launch-1.0:4831): GStreamer-CRITICAL **: gst_value_intersect: assertion 'G_IS_VALUE (value1)' failed The pipeline normally does not assert, but errors out: $ rm core ; while ! test -f core; do GST_DEBUG_FILE=gst.log GST_DEBUG=5,*alsa*:9,*CAPS*:9 G_DEBUG=fatal_warnings gst-launch-1.0 filesrc location=/home/v/Samples/8.wav ! wavparse ! audioconvert ! audioresample ! queue name=q48 filesrc location=/home/v/Samples/6.wav ! wavparse ! audioconvert ! audioresample ! queue name=q44 adder name=mix ! queue ! audioconvert ! alsasink q44. ! mix. q48. ! mix. ; done Normal output: Setting pipeline to PAUSED ... Pipeline is PREROLLING ... ERROR: from element /GstPipeline:pipeline0/GstWavParse:wavparse0: Internal data flow error. Additional debug info: gstwavparse.c(2168): gst_wavparse_loop (): /GstPipeline:pipeline0/GstWavParse:wavparse0: streaming task paused, reason not-negotiated (-4) ERROR: pipeline doesn't want to preroll. Setting pipeline to NULL ... Freeing pipeline ... It turns out there is a race condition somewhere which causes alsasink to use a caps in _query_caps which it also deletes in _close. One thread is the wavparse loop pushing:
+ Trace 233657
The other is alsasink closing out as the pipeline gets shutdown after the error. Sometimes, _close gets called early enough that it unrefs the cached caps which the other thread tries to use in the intersection. The sequence of events seems to be: - pipeline goes to PAUSED - alsasink goes to PAUSED, async - since it's async, the current state is not committed and stays in READY - wavparse goes to PAUSED - wavparse pushes in _loop - push fails - pipeline goes to NULL - since alsasink is in READY, it does one down to NULL - alsasink's _close is called, which unrefs the cached caps - caps are queried, which uses the cached caps while they're being destroyed I'm not sure why _loop is still running there, since it's been paused by the failure to push, and an error was sent to the bus. It seems it's that same wavparse, not the other.
commit 3b2d5833732a29672689badf3edf69867679e052 Author: Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> Date: Tue Jun 3 15:10:33 2014 +0100 alsasink: fix occasional crash intersecting invalid values When a pipeline using alsasink and push mode upstream fails to preroll, the following state will be the case: - A loop upstream will be PAUSED, pushing a first buffer - alsasink will be READY, pending PAUSED, because async On error, the pipeline will switch to NULL. alsasink is in READY, so goes to NULL immediately. It zeroes its cached caps. Meanwhile, the upstream loop can cause a caps query, conccurent with the state change. This will use those cached caps. If the zeroing happens between the NULL test and the dereferencing, GStreamer will critical down in the GstValue code. Since it appears that such a gap between states (PAUSED and pushing upstream, and NULL downstream) is expected, we need to protect the read/write access to the cached caps. This fixes the critical. See https://bugzilla.gnome.org/show_bug.cgi?id=731121