diff --git a/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.c b/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.c index 4fb80f1026..894b03f738 100644 --- a/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.c +++ b/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.c @@ -933,6 +933,23 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, send_message (client, ctx, ctx->response, FALSE); } +static void +send_generic_error_response (GstRTSPClient * client, GstRTSPStatusCode code, + GstRTSPContext * ctx) +{ + GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client); + GstRTSPStatusCode adjusted_code = code; + + if (klass->adjust_error_code != NULL) { + adjusted_code = klass->adjust_error_code (client, ctx, code); + if (adjusted_code != code) { + GST_DEBUG ("adjusted response error code from %d to %d", code, + adjusted_code); + } + } + send_generic_response (client, adjusted_code, ctx); +} + static void send_option_not_supported_response (GstRTSPClient * client, GstRTSPContext * ctx, const gchar * unsupported_options) @@ -1053,7 +1070,7 @@ find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path, no_factory: { GST_ERROR ("client %p: no factory for path %s", client, path); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return NULL; } no_factory_access: @@ -1076,7 +1093,7 @@ not_authorized: no_media: { GST_ERROR ("client %p: can't create media", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); gst_rtsp_url_free (url); g_object_unref (factory); ctx->factory = NULL; @@ -1085,7 +1102,7 @@ no_media: no_thread: { GST_ERROR ("client %p: can't create thread", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); gst_rtsp_url_free (url); g_object_unref (media); ctx->media = NULL; @@ -1096,7 +1113,7 @@ no_thread: no_prepare: { GST_ERROR ("client %p: can't prepare media", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); gst_rtsp_url_free (url); g_object_unref (media); ctx->media = NULL; @@ -1523,26 +1540,26 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) no_session: { GST_ERROR ("client %p: no session", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: no media for uri", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_free (path); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - send_generic_response (client, + send_generic_error_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); g_free (path); g_object_unref (sessmedia); @@ -1552,7 +1569,7 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -1627,13 +1644,13 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); return FALSE; } bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } } @@ -1679,13 +1696,13 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); return FALSE; } bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } } @@ -1774,26 +1791,26 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) no_session: { GST_ERROR ("client %p: no session", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: no media for uri", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); g_free (path); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - send_generic_response (client, + send_generic_error_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); g_object_unref (sessmedia); g_free (path); @@ -1803,7 +1820,7 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); gst_rtsp_media_unlock (media); g_object_unref (sessmedia); g_object_unref (media); @@ -1812,8 +1829,8 @@ sig_failed: invalid_state: { GST_ERROR ("client %p: not PLAYING or RECORDING", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - ctx); + send_generic_error_response (client, + GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); gst_rtsp_media_unlock (media); g_object_unref (sessmedia); g_object_unref (media); @@ -1822,7 +1839,7 @@ invalid_state: not_supported: { GST_ERROR ("client %p: pausing not supported", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); gst_rtsp_media_unlock (media); g_object_unref (sessmedia); g_object_unref (media); @@ -2196,25 +2213,25 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) no_session: { GST_ERROR ("client %p: no session", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: media not found", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - send_generic_response (client, + send_generic_error_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); g_object_unref (sessmedia); g_free (path); @@ -2224,7 +2241,7 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2233,8 +2250,8 @@ sig_failed: invalid_state: { GST_ERROR ("client %p: not PLAYING or READY", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - ctx); + send_generic_error_response (client, + GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2243,8 +2260,8 @@ invalid_state: pipeline_error: { GST_ERROR ("client %p: failed to configure the pipeline", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - ctx); + send_generic_error_response (client, + GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2253,7 +2270,7 @@ pipeline_error: unsuspend_failed: { GST_ERROR ("client %p: unsuspend failed", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2262,7 +2279,7 @@ unsuspend_failed: invalid_mode: { GST_ERROR ("client %p: seek failed", client); - send_generic_response (client, code, ctx); + send_generic_error_response (client, code, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2271,7 +2288,7 @@ invalid_mode: unsupported_mode: { GST_ERROR ("client %p: media does not support PLAY", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2280,7 +2297,8 @@ unsupported_mode: get_rates_error: { GST_ERROR ("client %p: failed obtaining rate and applied_rate", client); - send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); + send_generic_error_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, + ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2289,7 +2307,7 @@ get_rates_error: adjust_play_response_failed: { GST_ERROR ("client %p: failed to adjust play response", client); - send_generic_response (client, code, ctx); + send_generic_error_response (client, code, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2298,7 +2316,8 @@ adjust_play_response_failed: rtp_info_error: { GST_ERROR ("client %p: failed to add RTP-Info", client); - send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx); + send_generic_error_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, + ctx); gst_rtsp_media_unlock (media); g_object_unref (media); g_object_unref (sessmedia); @@ -2396,7 +2415,7 @@ done: parse_failed: { GST_ERROR_OBJECT (client, "failed to parse blocksize"); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } } @@ -3085,19 +3104,20 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) no_uri: { GST_ERROR ("client %p: no uri", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } no_transport: { GST_ERROR ("client %p: no transport", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, + ctx); goto cleanup_path; } no_pool: { GST_ERROR ("client %p: no session pool configured", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); goto cleanup_path; } media_not_found_no_reply: @@ -3109,13 +3129,13 @@ media_not_found_no_reply: media_not_found: { GST_ERROR ("client %p: media '%s' not found", client, path); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); goto cleanup_session; } control_not_found: { GST_ERROR ("client %p: no control in path '%s'", client, path); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_session; @@ -3124,7 +3144,7 @@ stream_not_found: { GST_ERROR ("client %p: stream '%s' not found", client, GST_STR_NULL (control)); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_session; @@ -3133,7 +3153,7 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_path; @@ -3141,7 +3161,7 @@ sig_failed: service_unavailable: { GST_ERROR ("client %p: can't create session", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); gst_rtsp_media_unlock (media); g_object_unref (media); goto cleanup_session; @@ -3149,7 +3169,7 @@ service_unavailable: sessmedia_unavailable: { GST_ERROR ("client %p: can't create session media", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); goto cleanup_transport; } configure_media_failed_no_reply: @@ -3163,13 +3183,15 @@ configure_media_failed_no_reply: unsupported_transports: { GST_ERROR ("client %p: unsupported transports", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, + ctx); goto cleanup_transport; } unsupported_client_transport: { GST_ERROR ("client %p: unsupported client transport", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, + ctx); goto cleanup_transport; } unsupported_mode: @@ -3180,20 +3202,22 @@ unsupported_mode: GST_RTSP_TRANSPORT_MODE_PLAY), ! !(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx); + send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, + ctx); goto cleanup_transport; } unsupported_range_unit: { GST_ERROR ("Client %p: does not support any range format we support", client); - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx); goto cleanup_transport; } keymgmt_error: { GST_ERROR ("client %p: keymgmt error", client); - send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx); + send_generic_error_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, + ctx); goto cleanup_transport; } { @@ -3362,25 +3386,25 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } no_mount_points: { GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_path: { GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_media: @@ -3393,7 +3417,7 @@ no_media: unsupported_mode: { GST_ERROR ("client %p: media does not support DESCRIBE", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); gst_rtsp_media_unlock (media); g_object_unref (media); @@ -3402,7 +3426,7 @@ unsupported_mode: no_sdp: { GST_ERROR ("client %p: can't create SDP", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); g_free (path); gst_rtsp_media_unlock (media); g_object_unref (media); @@ -3555,38 +3579,38 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) no_uri: { GST_ERROR ("client %p: no uri", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } no_mount_points: { GST_ERROR ("client %p: no mount points configured", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_path: { GST_ERROR ("client %p: can't find path for url", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); gst_sdp_message_free (sdp); return FALSE; } wrong_content_type: { GST_ERROR ("client %p: unknown content type", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } no_message: { GST_ERROR ("client %p: can't find SDP message", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } sdp_parse_failed: { GST_ERROR ("client %p: failed to parse SDP message", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); gst_sdp_message_free (sdp); return FALSE; } @@ -3602,7 +3626,7 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); gst_sdp_message_free (sdp); gst_rtsp_media_unlock (media); g_object_unref (media); @@ -3611,7 +3635,7 @@ sig_failed: unsupported_mode: { GST_ERROR ("client %p: media does not support ANNOUNCE", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); g_free (path); gst_rtsp_media_unlock (media); g_object_unref (media); @@ -3621,7 +3645,8 @@ unsupported_mode: unhandled_sdp: { GST_ERROR ("client %p: can't handle SDP", client); - send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx); + send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, + ctx); g_free (path); gst_rtsp_media_unlock (media); g_object_unref (media); @@ -3712,25 +3737,25 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) no_session: { GST_ERROR ("client %p: no session", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); return FALSE; } no_uri: { GST_ERROR ("client %p: no uri supplied", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); return FALSE; } not_found: { GST_ERROR ("client %p: media not found", client); - send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx); return FALSE; } no_aggregate: { GST_ERROR ("client %p: no aggregate path %s", client, path); - send_generic_response (client, + send_generic_error_response (client, GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx); g_free (path); return FALSE; @@ -3739,33 +3764,33 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); return FALSE; } unsupported_mode: { GST_ERROR ("client %p: media does not support RECORD", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); + send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx); return FALSE; } invalid_state: { GST_ERROR ("client %p: not PLAYING or READY", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - ctx); + send_generic_error_response (client, + GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); return FALSE; } pipeline_error: { GST_ERROR ("client %p: failed to configure the pipeline", client); - send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, - ctx); + send_generic_error_response (client, + GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx); return FALSE; } unsuspend_failed: { GST_ERROR ("client %p: unsuspend failed", client); - send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); + send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx); return FALSE; } } @@ -3816,7 +3841,7 @@ sig_failed: { GST_ERROR ("client %p: pre signal returned error: %s", client, gst_rtsp_status_as_text (sig_result)); - send_generic_response (client, sig_result, ctx); + send_generic_error_response (client, sig_result, ctx); gst_rtsp_message_free (ctx->response); return FALSE; } @@ -4130,32 +4155,32 @@ done: not_supported: { GST_ERROR ("client %p: version %d not supported", client, version); - send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, - ctx); + send_generic_error_response (client, + GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, ctx); goto done; } invalid_command_for_version: { GST_ERROR ("client %p: invalid command for version", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); goto done; } bad_request: { GST_ERROR ("client %p: bad request", client); - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); goto done; } no_pool: { GST_ERROR ("client %p: no pool configured", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); goto done; } session_not_found: { GST_ERROR ("client %p: session not found", client); - send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); + send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx); goto done; } not_authorized: @@ -4175,7 +4200,7 @@ unsupported_requirement: not_implemented: { GST_ERROR ("client %p: method %d not implemented", client, method); - send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx); + send_generic_error_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx); goto done; } } @@ -5043,11 +5068,12 @@ error_full (GstRTSPWatch * watch, GstRTSPResult result, goto done; if (result == GST_RTSP_ENOMEM) { - send_generic_response (client, GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE, ctx); + send_generic_error_response (client, GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE, + ctx); goto done; } if (result == GST_RTSP_EPARSE) { - send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); + send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx); goto done; } diff --git a/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.h b/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.h index 604a042399..ad1a024cee 100644 --- a/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.h +++ b/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.h @@ -115,6 +115,8 @@ struct _GstRTSPClient { * parsed when #GstRTSPClientClass.adjust_play_mode was called. Since 1.18 * @tunnel_http_response: called when a response to the GET request is about to * be sent for a tunneled connection. The response can be modified. Since: 1.4 + * @adjust_error_code: called before sending error response to give the + * application the possibility to adjust the error code. * * The client class structure. */ @@ -176,8 +178,10 @@ struct _GstRTSPClientClass { GstRTSPStatusCode (*pre_announce_request) (GstRTSPClient *client, GstRTSPContext *ctx); GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*adjust_error_code) (GstRTSPClient *client, GstRTSPContext *ctx, GstRTSPStatusCode code); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-18]; + gpointer _gst_reserved[GST_PADDING_LARGE-19]; }; GST_RTSP_SERVER_API diff --git a/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c b/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c index 035ea5b629..57db50556a 100644 --- a/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c +++ b/subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c @@ -217,6 +217,7 @@ enum SIGNAL_UNPREPARED, SIGNAL_TARGET_STATE, SIGNAL_NEW_STATE, + SIGNAL_HANDLE_MESSAGE, SIGNAL_LAST }; @@ -451,6 +452,23 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass) G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); + /** + * GstRTSPMedia::handle-message: + * @media: a #GstRTSPMedia + * @message: a #GstMessage + * + * Will be emitted when a message appears on the pipeline bus. + * + * Returns: a #gboolean indicating if the call was successful or not. + * + * Since: 1.22 + */ + gst_rtsp_media_signals[SIGNAL_HANDLE_MESSAGE] = + g_signal_new ("handle-message", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, G_STRUCT_OFFSET (GstRTSPMediaClass, + handle_message), NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, + GST_TYPE_MESSAGE); + GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); klass->handle_message = default_handle_message; @@ -3381,19 +3399,20 @@ static gboolean bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media) { GstRTSPMediaPrivate *priv = media->priv; - GstRTSPMediaClass *klass; + GQuark detail = 0; gboolean ret; - klass = GST_RTSP_MEDIA_GET_CLASS (media); + detail = gst_message_type_to_quark (GST_MESSAGE_TYPE (message)); g_rec_mutex_lock (&priv->state_lock); - if (klass->handle_message) - ret = klass->handle_message (media, message); - else - ret = FALSE; + g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_HANDLE_MESSAGE], detail, + message, &ret); + if (!ret) { + GST_DEBUG_OBJECT (media, "failed emitting pipeline message"); + } g_rec_mutex_unlock (&priv->state_lock); - return ret; + return TRUE; } static void diff --git a/subprojects/gst-rtsp-server/tests/check/gst/client.c b/subprojects/gst-rtsp-server/tests/check/gst/client.c index c65ae01ae4..943406aaf9 100644 --- a/subprojects/gst-rtsp-server/tests/check/gst/client.c +++ b/subprojects/gst-rtsp-server/tests/check/gst/client.c @@ -2128,7 +2128,79 @@ GST_START_TEST (test_client_play_root_mount_point) test_client_play_sub ("/", "rtsp://localhost/stream=0", "rtsp://localhost"); } -GST_END_TEST static Suite * +GST_END_TEST; + +#define RTSP_CLIENT_TEST_TYPE (rtsp_client_test_get_type ()) +#define RTSP_CLIENT_TEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RTSP_CLIENT_TEST_TYPE, RtspClientTestClass)) + +typedef struct RtspClientTest +{ + GstRTSPClient parent; +} RtspClientTest; + +typedef struct RtspClientTestClass +{ + GstRTSPClientClass parent_class; +} RtspClientTestClass; + +GType rtsp_client_test_get_type (void); + +G_DEFINE_TYPE (RtspClientTest, rtsp_client_test, GST_TYPE_RTSP_CLIENT); + +static void +rtsp_client_test_init (RtspClientTest * client) +{ +} + +static void +rtsp_client_test_class_init (RtspClientTestClass * klass) +{ +} + +static GstRTSPStatusCode +adjust_error_code_cb (GstRTSPClient * client, GstRTSPContext * ctx, + GstRTSPStatusCode code) +{ + return GST_RTSP_STS_NOT_FOUND; +} + +GST_START_TEST (test_adjust_error_code) +{ + RtspClientTest *client; + RtspClientTestClass *klass; + GstRTSPClientClass *base_klass; + GstRTSPMessage request = { 0, }; + + client = g_object_new (RTSP_CLIENT_TEST_TYPE, NULL); + + /* invalid request to trigger error response */ + ck_assert (gst_rtsp_message_init_request (&request, GST_RTSP_INVALID, + "foopy://padoop/") == GST_RTSP_OK); + + /* expect non-adjusted error response 400 */ + gst_rtsp_client_set_send_func (GST_RTSP_CLIENT (client), test_response_400, + NULL, NULL); + ck_assert (gst_rtsp_client_handle_message (GST_RTSP_CLIENT (client), + &request) == GST_RTSP_OK); + + /* override virtual function for adjusting error code */ + klass = RTSP_CLIENT_TEST_GET_CLASS (client); + base_klass = GST_RTSP_CLIENT_CLASS (klass); + base_klass->adjust_error_code = adjust_error_code_cb; + + /* expect error adjusted to 404 */ + gst_rtsp_client_set_send_func (GST_RTSP_CLIENT (client), test_response_404, + NULL, NULL); + ck_assert (gst_rtsp_client_handle_message (GST_RTSP_CLIENT (client), + &request) == GST_RTSP_OK); + + gst_rtsp_message_unset (&request); + g_object_unref (client); +} + +GST_END_TEST; + +static Suite * rtspclient_suite (void) { Suite *s = suite_create ("rtspclient"); @@ -2188,6 +2260,7 @@ rtspclient_suite (void) tcase_add_test (tc, test_scale_and_speed); tcase_add_test (tc, test_client_play); tcase_add_test (tc, test_client_play_root_mount_point); + tcase_add_test (tc, test_adjust_error_code); return s; } diff --git a/subprojects/gst-rtsp-server/tests/check/gst/media.c b/subprojects/gst-rtsp-server/tests/check/gst/media.c index 0284753d7f..4a71adcdbc 100644 --- a/subprojects/gst-rtsp-server/tests/check/gst/media.c +++ b/subprojects/gst-rtsp-server/tests/check/gst/media.c @@ -863,6 +863,67 @@ GST_START_TEST (test_media_multidyn_prepare) GST_END_TEST; +static gboolean +pipeline_error (GstRTSPMedia * media, GstMessage * message, guint * data) +{ + GError *gerror = NULL; + + /* verify that the correct error was received */ + gst_message_parse_error (message, &gerror, NULL); + ck_assert_str_eq (GST_MESSAGE_SRC_NAME (message), "src0"); + ck_assert_ptr_ne (gerror, NULL); + ck_assert_int_eq (gerror->domain, GST_STREAM_ERROR); + ck_assert_int_eq (gerror->code, GST_STREAM_ERROR_FAILED); + ck_assert_str_eq (gerror->message, "Internal data stream error."); + (*data)++; + + return TRUE; +} + +GST_START_TEST (test_media_pipeline_error) +{ + GstRTSPMediaFactory *factory; + GstRTSPMedia *media; + GstRTSPUrl *url; + GstRTSPThreadPool *pool; + GstRTSPThread *thread; + guint handled_messages = 0; + + pool = gst_rtsp_thread_pool_new (); + + factory = gst_rtsp_media_factory_new (); + ck_assert (!gst_rtsp_media_factory_is_shared (factory)); + ck_assert (gst_rtsp_url_parse ("rtsp://localhost:8554/test", + &url) == GST_RTSP_OK); + + /* add faulty caps filter to fail linking when preparing media, this will + * result in an error being posted on the pipelines bus. */ + gst_rtsp_media_factory_set_launch (factory, + "( videotestsrc name=src0 ! video/fail_prepare ! rtpvrawpay pt=96 name=pay0 )"); + + media = gst_rtsp_media_factory_construct (factory, url); + ck_assert (GST_IS_RTSP_MEDIA (media)); + ck_assert_int_eq (gst_rtsp_media_n_streams (media), 1); + + /* subscribe to pipeline errors */ + g_signal_connect (media, "handle-message::error", G_CALLBACK (pipeline_error), + &handled_messages); + + thread = gst_rtsp_thread_pool_get_thread (pool, + GST_RTSP_THREAD_TYPE_MEDIA, NULL); + ck_assert (!gst_rtsp_media_prepare (media, thread)); + ck_assert_uint_eq (handled_messages, 1); + + g_object_unref (media); + gst_rtsp_url_free (url); + g_object_unref (factory); + + g_object_unref (pool); + gst_rtsp_thread_pool_cleanup (); +} + +GST_END_TEST; + static Suite * rtspmedia_suite (void) @@ -893,6 +954,7 @@ rtspmedia_suite (void) tcase_add_test (tc, test_media_take_pipeline); tcase_add_test (tc, test_media_reset); tcase_add_test (tc, test_media_multidyn_prepare); + tcase_add_test (tc, test_media_pipeline_error); return s; }