summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2011-10-25 04:36:46 +0000
committerBenny Prijono <bennylp@teluu.com>2011-10-25 04:36:46 +0000
commitca7ea8021109780ad4dc3d8ef21650ae9779b555 (patch)
tree1b3c883e350dcb0f668b3e92a2ed90d128c2b866
parent14048edf1d8463b6f72e4cf1df0c3827309f2adc (diff)
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
-rw-r--r--pjmedia/src/pjmedia/vid_stream.c41
1 files 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) {