GNOME Bugzilla – Bug 696675
basesink: state change issue when adding alsasink dynamically
Last modified: 2013-07-24 09:37:23 UTC
Created attachment 239930 [details] Trace While using alsasink element in a bin in a dynamic pipeline, I faced an issue when this bin selecting alsasink is already in PLAYING state. In such a case, alsasink might block in GST_BASE_SINK_PREROLL_WAIT() in gst_base_sink_wait_preroll(). Indeed, if the bin is already in PLAYING state and alsasink's state is synchronized on its parent, the pending state will be playing. Then, if gst_base_sink_do_preroll() is called before ASYNC set states have been performed, it will commit the state to PLAYING. Doing this, will prevent from calling gst_audio_base_sink_change_state() where important things are performed. Indeed, in the transition from pause to playing, gst_audio_ring_buffer_may_start() is called and set to true, and because it does not pass through this step in the conditions described above, it will block in preroll_wait. Indeed, in gst_base_sink_chain_unlocked(), after committing to PLAYING state, render function of gstaudiobasesink is called and there it tries to render the buffer and write it in the ringbuffer which has not been started (gst_audio_base_sink_change_state() not called), the condition written==samples is not satisfied, gst_base_sink_wait_preroll() is called and it is stuck there. In the patch in attachment, I added the call to gst_element_change_state() in gst_base_sink_commit_state() when committing to PLAYING state. It is not necessary to call it when committing to PAUSE state as the method is called before returning GST_STATE_CHANGE_ASYNC from the function setting the state. I am not sure so far if this is a correct solution and comments would be greatly appreciated :)
Created attachment 239931 [details] [review] Patch
It does indeed not call the state_change function and it should do that. I think your patch is however racy. It is possible that while you call the gst_element_change_state() a concurrent state change might happen. I think it somehow needs to take the STATE_LOCK as is a requirement for gst_element_change_state(). I will have a deeper look because this code should theoretically be similar to how the bin continues its state.
Here is another racy attempt: http://cgit.freedesktop.org/~wtay/gstreamer/log/?h=sink-states I'm now thinking that we need to release the stream-lock before getting the state-lock..
Thx Wim for your feedback, I gonna try your fix.
Wim, any news on this?
I think this is: commit 124b8e38afa5a7e18b01d8f5969b7b20b9854030 Author: Wim Taymans <wim.taymans@collabora.co.uk> Date: Mon Jun 17 10:25:20 2013 +0200 basesink: call state change in all cases When we asynchronously go from READY to PLAYING, also call the state change function so that subclasses can update their state for PLAYING. Because the PREROLL lock is not recursive, we can't make this without races and we must assume for now that the subclass can handle concurrent calls to PAUSED->PLAYING and PLAYING->PAUSED. We can make this assumption because not many elements actually do something in those state changes and the ones that did would be broken even more without this change. https://bugzilla.gnome.org/show_bug.cgi?id=702282
*** This bug has been marked as a duplicate of bug 702282 ***