@@ -158,6 +158,7 @@ void rtsp_session_init(rtsp_session_t *session)
158158 session -> last_keepalive_ms = 0 ;
159159 session -> keepalive_pending = 0 ;
160160 session -> awaiting_keepalive_response = 0 ;
161+ session -> use_get_parameter = 1 ; /* Start with GET_PARAMETER, fallback to OPTIONS if not supported */
161162
162163 /* Initialize teardown state */
163164 session -> teardown_requested = 0 ;
@@ -175,6 +176,8 @@ static void rtsp_session_set_state(rtsp_session_t *session, rtsp_state_t new_sta
175176 [RTSP_STATE_INIT ] = CLIENT_STATE_RTSP_INIT ,
176177 [RTSP_STATE_CONNECTING ] = CLIENT_STATE_RTSP_CONNECTING ,
177178 [RTSP_STATE_CONNECTED ] = CLIENT_STATE_RTSP_CONNECTED ,
179+ [RTSP_STATE_SENDING_OPTIONS ] = CLIENT_STATE_RTSP_SENDING_OPTIONS ,
180+ [RTSP_STATE_AWAITING_OPTIONS ] = CLIENT_STATE_RTSP_AWAITING_OPTIONS ,
178181 [RTSP_STATE_SENDING_DESCRIBE ] = CLIENT_STATE_RTSP_SENDING_DESCRIBE ,
179182 [RTSP_STATE_AWAITING_DESCRIBE ] = CLIENT_STATE_RTSP_AWAITING_DESCRIBE ,
180183 [RTSP_STATE_DESCRIBED ] = CLIENT_STATE_RTSP_DESCRIBED ,
@@ -945,13 +948,15 @@ int rtsp_send_keepalive(rtsp_session_t *session)
945948 char extra_headers [RTSP_HEADERS_BUFFER_SIZE ];
946949 if (snprintf (extra_headers , sizeof (extra_headers ), "Session: %s\r\n" , session -> session_id ) >= (int )sizeof (extra_headers ))
947950 {
948- logger (LOG_ERROR , "RTSP: Failed to format OPTIONS keepalive headers" );
951+ logger (LOG_ERROR , "RTSP: Failed to format keepalive headers" );
949952 return -1 ;
950953 }
951954
952- if (rtsp_prepare_request (session , RTSP_METHOD_OPTIONS , extra_headers ) < 0 )
955+ /* Use GET_PARAMETER if supported, otherwise use OPTIONS */
956+ const char * method = session -> use_get_parameter ? RTSP_METHOD_GET_PARAMETER : RTSP_METHOD_OPTIONS ;
957+ if (rtsp_prepare_request (session , method , extra_headers ) < 0 )
953958 {
954- logger (LOG_ERROR , "RTSP: Failed to prepare OPTIONS keepalive request" );
959+ logger (LOG_ERROR , "RTSP: Failed to prepare %s keepalive request" , method );
955960 return -1 ;
956961 }
957962
@@ -964,15 +969,15 @@ int rtsp_send_keepalive(rtsp_session_t *session)
964969 ev .data .fd = session -> socket ;
965970 if (epoll_ctl (session -> epoll_fd , EPOLL_CTL_MOD , session -> socket , & ev ) < 0 )
966971 {
967- logger (LOG_ERROR , "RTSP: Failed to enable EPOLLOUT for OPTIONS keepalive: %s" , strerror (errno ));
972+ logger (LOG_ERROR , "RTSP: Failed to enable EPOLLOUT for %s keepalive: %s" , method , strerror (errno ));
968973 session -> pending_request_len = 0 ;
969974 session -> pending_request_sent = 0 ;
970975 session -> keepalive_pending = 0 ;
971976 return -1 ;
972977 }
973978 }
974979
975- logger (LOG_DEBUG , "RTSP: Queued OPTIONS keepalive request" );
980+ logger (LOG_DEBUG , "RTSP: Queued %s keepalive request" , method );
976981 return 0 ;
977982}
978983
@@ -1023,7 +1028,11 @@ static int rtsp_try_send_pending(rtsp_session_t *session)
10231028 }
10241029
10251030 /* Update state to awaiting response */
1026- if (session -> state == RTSP_STATE_SENDING_DESCRIBE )
1031+ if (session -> state == RTSP_STATE_SENDING_OPTIONS )
1032+ {
1033+ rtsp_session_set_state (session , RTSP_STATE_AWAITING_OPTIONS );
1034+ }
1035+ else if (session -> state == RTSP_STATE_SENDING_DESCRIBE )
10271036 {
10281037 rtsp_session_set_state (session , RTSP_STATE_AWAITING_DESCRIBE );
10291038 }
@@ -1122,11 +1131,19 @@ static int rtsp_try_receive_response(rtsp_session_t *session)
11221131 if (was_keepalive )
11231132 {
11241133 session -> response_buffer_pos = 0 ;
1125- logger (LOG_DEBUG , "RTSP: OPTIONS keepalive acknowledged" );
1134+ const char * method = session -> use_get_parameter ? "GET_PARAMETER" : "OPTIONS" ;
1135+ logger (LOG_DEBUG , "RTSP: %s keepalive acknowledged" , method );
11261136 return RTSP_RESPONSE_KEEPALIVE ;
11271137 }
11281138
11291139 /* Advance to next state based on current state */
1140+ if (session -> state == RTSP_STATE_AWAITING_OPTIONS )
1141+ {
1142+ /* OPTIONS response received - keep state as AWAITING_OPTIONS,
1143+ * state machine will transition to SENDING_DESCRIBE */
1144+ session -> response_buffer_pos = 0 ;
1145+ return RTSP_RESPONSE_ADVANCE ;
1146+ }
11301147 if (session -> state == RTSP_STATE_AWAITING_DESCRIBE )
11311148 {
11321149 rtsp_session_set_state (session , RTSP_STATE_DESCRIBED );
@@ -1179,7 +1196,19 @@ static int rtsp_state_machine_advance(rtsp_session_t *session)
11791196 switch (session -> state )
11801197 {
11811198 case RTSP_STATE_CONNECTED :
1182- /* Ready to send DESCRIBE */
1199+ /* Ready to send OPTIONS (RFC 2326 requires OPTIONS before DESCRIBE) */
1200+ extra_headers [0 ] = '\0' ; /* No extra headers needed for OPTIONS */
1201+ if (rtsp_prepare_request (session , RTSP_METHOD_OPTIONS , extra_headers ) < 0 )
1202+ {
1203+ logger (LOG_ERROR , "RTSP: Failed to prepare OPTIONS request" );
1204+ return -1 ;
1205+ }
1206+ rtsp_session_set_state (session , RTSP_STATE_SENDING_OPTIONS );
1207+ /* Will send when socket becomes writable */
1208+ return 0 ;
1209+
1210+ case RTSP_STATE_AWAITING_OPTIONS :
1211+ /* OPTIONS response received, ready to send DESCRIBE */
11831212 snprintf (extra_headers , sizeof (extra_headers ), "Accept: application/sdp\r\n" );
11841213 if (rtsp_prepare_request (session , RTSP_METHOD_DESCRIBE , extra_headers ) < 0 )
11851214 {
@@ -1496,6 +1525,7 @@ static void rtsp_force_cleanup(rtsp_session_t *session)
14961525 session -> last_keepalive_ms = 0 ;
14971526 session -> keepalive_pending = 0 ;
14981527 session -> awaiting_keepalive_response = 0 ;
1528+ session -> use_get_parameter = 1 ;
14991529
15001530 /* Reset teardown state */
15011531 session -> teardown_requested = 0 ;
@@ -1694,6 +1724,7 @@ static int rtsp_parse_response(rtsp_session_t *session, const char *response)
16941724 char * session_header = NULL ;
16951725 char * transport_header = NULL ;
16961726 char * location_header = NULL ;
1727+ char * public_header = NULL ;
16971728 int status_code ;
16981729 int result = 0 ;
16991730
@@ -1725,11 +1756,48 @@ static int rtsp_parse_response(rtsp_session_t *session, const char *response)
17251756 }
17261757 else if (status_code != 200 )
17271758 {
1759+ /* Check if this is a GET_PARAMETER not supported error during keepalive */
1760+ if ((status_code == 454 || status_code == 501 ) &&
1761+ session -> awaiting_keepalive_response && session -> use_get_parameter )
1762+ {
1763+ logger (LOG_DEBUG , "RTSP: GET_PARAMETER not supported (code %d), falling back to OPTIONS for keepalive" , status_code );
1764+ session -> use_get_parameter = 0 ;
1765+ session -> awaiting_keepalive_response = 0 ;
1766+ result = 0 ; /* Treat as success, will use OPTIONS next time */
1767+ goto cleanup ;
1768+ }
1769+
17281770 logger (LOG_ERROR , "RTSP: Server returned error code %d" , status_code );
17291771 result = -1 ;
17301772 goto cleanup ;
17311773 }
17321774
1775+ /* Parse Public header from OPTIONS response to determine supported methods */
1776+ if (session -> state == RTSP_STATE_AWAITING_OPTIONS )
1777+ {
1778+ public_header = rtsp_find_header (response , "Public" );
1779+ if (public_header )
1780+ {
1781+ /* Check if GET_PARAMETER is supported */
1782+ if (strstr (public_header , "GET_PARAMETER" ))
1783+ {
1784+ session -> use_get_parameter = 1 ;
1785+ logger (LOG_DEBUG , "RTSP: Server supports GET_PARAMETER for keepalive" );
1786+ }
1787+ else
1788+ {
1789+ session -> use_get_parameter = 0 ;
1790+ logger (LOG_DEBUG , "RTSP: Server does not advertise GET_PARAMETER, will use OPTIONS for keepalive" );
1791+ }
1792+ logger (LOG_DEBUG , "RTSP: Server advertised methods: %s" , public_header );
1793+ }
1794+ else
1795+ {
1796+ /* No Public header - try GET_PARAMETER anyway, fallback on error */
1797+ logger (LOG_DEBUG , "RTSP: No Public header in OPTIONS response, will try GET_PARAMETER with fallback" );
1798+ }
1799+ }
1800+
17331801 /* Extract Session header if present */
17341802 session_header = rtsp_find_header (response , "Session" );
17351803 if (session_header )
@@ -1758,6 +1826,8 @@ static int rtsp_parse_response(rtsp_session_t *session, const char *response)
17581826 free (transport_header );
17591827 if (location_header )
17601828 free (location_header );
1829+ if (public_header )
1830+ free (public_header );
17611831
17621832 return result ;
17631833}
@@ -2128,6 +2198,7 @@ static void rtsp_parse_transport_header(rtsp_session_t *session, const char *tra
21282198 session -> last_keepalive_ms = 0 ;
21292199 session -> keepalive_pending = 0 ;
21302200 session -> awaiting_keepalive_response = 0 ;
2201+ session -> use_get_parameter = 1 ; /* Try GET_PARAMETER first, fallback to OPTIONS */
21312202 logger (LOG_INFO , "RTSP: Using UDP transport" );
21322203
21332204 /* Parse source parameter if provided */
0 commit comments