hlsdemux(?): deadlock while buffering a specific HLS stream
I've noticed that sometimes a deadlock happens while trying to play a specific HLS stream, which I'm hosting here. To reproduce, simply play the media in a loop and eventually gst-play-1.0
will get stuck displaying Buffering...
in stdout. For example, I can reproduce with:
while true; do
gst-play-1.0 https://sample-medias.herokuapp.com/static/gst_hls_dl_audio/audio_dl.m3u8
done
Brief investigation results
During my initial investigations I suspected that the problem was related to the values of the BANDWIDTH
fields in the master HLS manifest, since I noticed that some specific values make it very difficult to reproduce. It also seems to tie into the variant change logic, since if I change gst_hls_master_playlist_get_variant_for_bitrate
from m3u8.c
to always return the same variant (return current_variant ? current_variant : variant;
), the deadlock doesn't seem to happen at all.
While trying to fix this I also found another place where I can change some code to significantly decrease the chances of it happening: if I replace gst_hls_demux_clear_all_pending_data
in gsthlsdemux.c
with the version below, the deadlock becomes much harder to reproduce (although it still does happen):
static void
gst_hls_demux_clear_all_pending_data (GstHLSDemux * hlsdemux)
{
GstAdaptiveDemux *demux = (GstAdaptiveDemux *) hlsdemux;
GList *walk;
for (walk = demux->streams; walk != NULL; walk = walk->next) {
GstHLSDemuxStream *hls_stream = GST_HLS_DEMUX_STREAM_CAST (walk->data);
gst_hls_demux_stream_clear_pending_data (hls_stream);
GstAdaptiveDemuxStream *stream = &hls_stream->adaptive_demux_stream;
g_mutex_lock (&hls_stream->adaptive_demux_stream.fragment_download_lock);
hls_stream->adaptive_demux_stream.cancelled = TRUE;
g_cond_signal (&hls_stream->adaptive_demux_stream.fragment_download_cond);
g_mutex_unlock (&hls_stream->adaptive_demux_stream.fragment_download_lock);
}
}