From e4720e286ca217afdf43996ebe7e44c2aeab932c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 18 May 2007 10:36:12 +0000 Subject: [PATCH] gst/rtsp/gstrtspsrc.c: Refactor timeout handling. Original commit message from CVS: * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp), (gst_rtspsrc_try_send), (gst_rtspsrc_send), (gst_rtspsrc_setup_streams): Refactor timeout handling. Also send keep-alive when dealing with TCP transport. * gst/rtsp/rtspconnection.c: (rtsp_connection_create), (rtsp_connection_free), (rtsp_connection_next_timeout), (rtsp_connection_reset_timeout): * gst/rtsp/rtspconnection.h: Use a timer to handle the session timeouts, add some methods to deal with timeouts. --- ChangeLog | 16 +++++ gst/rtsp/gstrtspsrc.c | 146 ++++++++++++++++++++++---------------- gst/rtsp/rtspconnection.c | 36 ++++++++++ gst/rtsp/rtspconnection.h | 11 ++- 4 files changed, 146 insertions(+), 63 deletions(-) diff --git a/ChangeLog b/ChangeLog index 251ebc1e38..09924a5977 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2007-05-18 Wim Taymans + + * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send_keep_alive), + (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp), + (gst_rtspsrc_try_send), (gst_rtspsrc_send), + (gst_rtspsrc_setup_streams): + Refactor timeout handling. + Also send keep-alive when dealing with TCP transport. + + * gst/rtsp/rtspconnection.c: (rtsp_connection_create), + (rtsp_connection_free), (rtsp_connection_next_timeout), + (rtsp_connection_reset_timeout): + * gst/rtsp/rtspconnection.h: + Use a timer to handle the session timeouts, add some methods to deal + with timeouts. + 2007-05-17 Wim Taymans * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 1586171392..d7743a9899 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -2079,6 +2079,47 @@ send_error: } } +/* send server keep-alive */ +static RTSPResult +gst_rtspsrc_send_keep_alive (GstRTSPSrc * src) +{ + RTSPMessage request = { 0 }; + RTSPResult res; + RTSPMethod method; + + GST_DEBUG_OBJECT (src, "creating server keep-alive"); + + /* find a method to use for keep-alive */ + if (src->methods & RTSP_GET_PARAMETER) + method = RTSP_GET_PARAMETER; + else + method = RTSP_OPTIONS; + + res = rtsp_message_init_request (&request, method, src->req_location); + if (res < 0) + goto send_error; + + if ((res = rtsp_connection_send (src->connection, &request, NULL)) < 0) + goto send_error; + + rtsp_connection_reset_timeout (src->connection); + rtsp_message_unset (&request); + + return RTSP_OK; + + /* ERRORS */ +send_error: + { + gchar *str = rtsp_strresult (res); + + rtsp_message_unset (&request); + GST_ELEMENT_WARNING (src, RESOURCE, WRITE, (NULL), + ("Could not send keep-alive. (%s)", str)); + g_free (str); + return res; + } +} + static void gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) { @@ -2096,10 +2137,35 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) have_data = FALSE; do { + GTimeVal tv_timeout; + + /* get the next timeout interval */ + rtsp_connection_next_timeout (src->connection, &tv_timeout); + + /* see if the timeout period expired */ + if ((tv_timeout.tv_usec | tv_timeout.tv_usec) == 0) { + GST_DEBUG_OBJECT (src, "timout, sending keep-alive"); + /* send keep-alive, ignore the result, a warning will be posted. */ + res = gst_rtspsrc_send_keep_alive (src); + } + GST_DEBUG_OBJECT (src, "doing receive"); - if ((res = rtsp_connection_receive (src->connection, &message, NULL)) < 0) - goto receive_error; + res = rtsp_connection_receive (src->connection, &message, NULL); + + switch (res) { + case RTSP_OK: + GST_DEBUG_OBJECT (src, "we received a server message"); + break; + case RTSP_EINTR: + /* we got interrupted, see what we have to do */ + GST_DEBUG_OBJECT (src, "we got interrupted, unset flushing"); + /* unset flushing so we can do something else */ + rtsp_connection_flush (src->connection, FALSE); + goto interrupt; + default: + goto receive_error; + } switch (message.type) { case RTSP_MESSAGE_REQUEST: @@ -2200,6 +2266,13 @@ unknown_stream: rtsp_message_unset (&message); return; } +interrupt: + { + GST_DEBUG_OBJECT (src, "we got interrupted"); + rtsp_message_unset (&message); + ret = GST_FLOW_WRONG_STATE; + goto need_pause; + } receive_error: { gchar *str = rtsp_strresult (res); @@ -2260,49 +2333,6 @@ need_pause: } } -/* send server keep-alive */ -static RTSPResult -gst_rtspsrc_send_keep_alive (GstRTSPSrc * src) -{ - RTSPMessage request = { 0 }; - RTSPMessage response = { 0 }; - RTSPResult res; - RTSPStatusCode code; - RTSPMethod method; - - GST_DEBUG_OBJECT (src, "creating server keep-alive"); - - /* find a method to use for keep-alive */ - if (src->methods & RTSP_GET_PARAMETER) - method = RTSP_GET_PARAMETER; - else - method = RTSP_OPTIONS; - - res = rtsp_message_init_request (&request, method, src->req_location); - if (res < 0) - goto send_error; - - /* let us handle the error code because we don't care */ - if ((res = gst_rtspsrc_send (src, &request, &response, &code)) < 0) - goto send_error; - - rtsp_message_unset (&request); - - return RTSP_OK; - - /* ERRORS */ -send_error: - { - gchar *str = rtsp_strresult (res); - - rtsp_message_unset (&request); - GST_ELEMENT_WARNING (src, RESOURCE, WRITE, (NULL), - ("Could not send keep-alive. (%s)", str)); - g_free (str); - return res; - } -} - static void gst_rtspsrc_loop_udp (GstRTSPSrc * src) { @@ -2314,26 +2344,17 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src) goto stopping; while (src->loop_cmd == CMD_WAIT) { - GTimeVal tv_timeout; - gint timeout; - GST_OBJECT_UNLOCK (src); while (TRUE) { RTSPMessage message = { 0 }; + GTimeVal tv_timeout; - /* calculate the session timeout. We should send the keep-alive request a - * little earlier to compensate for the round trip time to the server. We - * subtract 1 second here. */ - timeout = src->connection->timeout; - if (timeout > 1) - timeout -= 1; + /* get the next timeout interval */ + rtsp_connection_next_timeout (src->connection, &tv_timeout); - /* use the session timeout for receiving data */ - tv_timeout.tv_sec = timeout; - tv_timeout.tv_usec = 0; - - GST_DEBUG_OBJECT (src, "doing receive with timeout %d seconds", timeout); + GST_DEBUG_OBJECT (src, "doing receive with timeout %d seconds", + tv_timeout.tv_sec); /* we should continue reading the TCP socket because the server might * send us requests. When the session timeout expires, we need to send a @@ -2366,9 +2387,12 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src) goto handle_request_failed; break; case RTSP_MESSAGE_RESPONSE: + /* we ignore response and data messages */ + GST_DEBUG_OBJECT (src, "ignoring response message"); + break; case RTSP_MESSAGE_DATA: /* we ignore response and data messages */ - GST_DEBUG_OBJECT (src, "ignoring message"); + GST_DEBUG_OBJECT (src, "ignoring data message"); break; default: GST_WARNING_OBJECT (src, "ignoring unknown message type %d", @@ -2673,6 +2697,8 @@ gst_rtspsrc_try_send (GstRTSPSrc * src, RTSPMessage * request, if ((res = rtsp_connection_send (src->connection, request, NULL)) < 0) goto send_error; + rtsp_connection_reset_timeout (src->connection); + next: if ((res = rtsp_connection_receive (src->connection, response, NULL)) < 0) goto receive_error; diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c index d806b50ae7..cb81c72c97 100644 --- a/gst/rtsp/rtspconnection.c +++ b/gst/rtsp/rtspconnection.c @@ -142,6 +142,7 @@ rtsp_connection_create (RTSPUrl * url, RTSPConnection ** conn) newconn->fd = -1; newconn->cseq = 0; newconn->session_id[0] = 0; + newconn->timer = g_timer_new (); newconn->auth_method = RTSP_AUTH_NONE; newconn->username = NULL; @@ -900,6 +901,7 @@ rtsp_connection_free (RTSPConnection * conn) WSACleanup (); #endif + g_timer_destroy (conn->timer); g_free (conn->username); g_free (conn->passwd); @@ -908,6 +910,40 @@ rtsp_connection_free (RTSPConnection * conn) return RTSP_OK; } +RTSPResult +rtsp_connection_next_timeout (RTSPConnection * conn, GTimeVal * timeout) +{ + gdouble elapsed; + glong sec; + gulong usec; + + g_return_val_if_fail (conn != NULL, RTSP_EINVAL); + g_return_val_if_fail (timeout != NULL, RTSP_EINVAL); + + elapsed = g_timer_elapsed (conn->timer, &usec); + if (elapsed >= conn->timeout) { + sec = 0; + usec = 0; + } else { + sec = conn->timeout - elapsed; + } + + timeout->tv_sec = sec; + timeout->tv_usec = usec; + + return RTSP_OK; +} + +RTSPResult +rtsp_connection_reset_timeout (RTSPConnection * conn) +{ + g_return_val_if_fail (conn != NULL, RTSP_EINVAL); + + g_timer_start (conn->timer); + + return RTSP_OK; +} + RTSPResult rtsp_connection_flush (RTSPConnection * conn, gboolean flush) { diff --git a/gst/rtsp/rtspconnection.h b/gst/rtsp/rtspconnection.h index b2fcd0723a..2827258796 100644 --- a/gst/rtsp/rtspconnection.h +++ b/gst/rtsp/rtspconnection.h @@ -65,11 +65,12 @@ typedef struct _RTSPConnection gint cseq; /* sequence number */ gchar session_id[512]; /* session id */ gint timeout; /* session timeout in seconds */ + GTimer *timer; /* timeout timer */ /* Authentication */ - RTSPAuthMethod auth_method; - gchar *username; - gchar *passwd; + RTSPAuthMethod auth_method; + gchar *username; + gchar *passwd; } RTSPConnection; /* opening/closing a connection */ @@ -88,6 +89,10 @@ RTSPResult rtsp_connection_write (RTSPConnection * conn, const guint8 * RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout); RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout); +/* reset the timeout */ +RTSPResult rtsp_connection_next_timeout (RTSPConnection *conn, GTimeVal *timeout); +RTSPResult rtsp_connection_reset_timeout (RTSPConnection *conn); + /* flushing state */ RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush);