From ca7ea8021109780ad4dc3d8ef21650ae9779b555 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 25 Oct 2011 04:36:46 +0000 Subject: More #1394: fixed deadlock when format change is reported by vid_stream, which cause the clock to stop. It waits for the callback to return, but the callback is waiting to lock the jb_mutex, which is currently being held by the stopping clock. The workaround is to queue the event and report it later git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3847 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/src/pjmedia/vid_stream.c | 41 +++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/pjmedia/src/pjmedia/vid_stream.c b/pjmedia/src/pjmedia/vid_stream.c index 72d7eea0..b89d251a 100644 --- a/pjmedia/src/pjmedia/vid_stream.c +++ b/pjmedia/src/pjmedia/vid_stream.c @@ -121,6 +121,8 @@ struct pjmedia_vid_stream unsigned dec_max_size; /**< Size of decoded/raw picture*/ pjmedia_frame dec_frame; /**< Current decoded frame. */ + pjmedia_event fmt_event; /**< Buffered fmt_changed event + to avoid deadlock */ unsigned frame_size; /**< Size of encoded base frame.*/ unsigned frame_ts_len; /**< Frame length in timestamp. */ @@ -346,20 +348,15 @@ static pj_status_t stream_event_cb(pjmedia_event_subscription *esub, /* This is codec event */ switch (event->type) { case PJMEDIA_EVENT_FMT_CHANGED: - /* Update param from codec */ - pjmedia_vid_codec_get_param(stream->codec, stream->info.codec_param); - - /* Update decoding channel port info */ - pjmedia_format_copy(&stream->dec->port.info.fmt, - &stream->info.codec_param->dec_fmt); - /* we process the event */ ++event->proc_cnt; - dump_port_info(event->data.fmt_changed.dir==PJMEDIA_DIR_DECODING ? - stream->dec : stream->enc, - "changed"); - break; + /* Copy the event to avoid deadlock if we publish the event + * now. This happens because fmt_event may trigger restart + * while we're still holding the jb_mutex. + */ + pj_memcpy(&stream->fmt_event, event, sizeof(*event)); + return PJ_SUCCESS; default: break; } @@ -1072,6 +1069,28 @@ static pj_status_t get_frame(pjmedia_port *port, return PJ_SUCCESS; } + /* Report pending events. Do not publish the event while holding the + * jb_mutex as that would lead to deadlock. It should be safe to + * operate on fmt_event without the mutex because format change normally + * would only occur once during the start of the media. + */ + if (stream->fmt_event.type != PJMEDIA_EVENT_NONE) { + /* Update param from codec */ + pjmedia_vid_codec_get_param(stream->codec, stream->info.codec_param); + + /* Update decoding channel port info */ + pjmedia_format_copy(&stream->dec->port.info.fmt, + &stream->info.codec_param->dec_fmt); + + dump_port_info(stream->fmt_event.data.fmt_changed.dir==PJMEDIA_DIR_DECODING ? + stream->dec : stream->enc, + "changed"); + + pjmedia_event_publish(&stream->epub, &stream->fmt_event); + + stream->fmt_event.type = PJMEDIA_EVENT_NONE; + } + pj_mutex_lock( stream->jb_mutex ); if (stream->dec_frame.size == 0) { -- cgit v1.2.3