From 8425ea696928971333a71ebf8f76e399cf13be5c Mon Sep 17 00:00:00 2001 From: Branko Subasic Date: Wed, 24 Aug 2016 11:39:13 +0200 Subject: [PATCH] client: emit signal in the beginning of each rtsp request These signals let the application validate the requests, configure the media/stream in a certain way and also generate error status code in case of error or bad request. https://bugzilla.gnome.org/show_bug.cgi?id=758062 --- gst/rtsp-server/rtsp-client.c | 386 ++++++++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-client.h | 13 +- 2 files changed, 398 insertions(+), 1 deletion(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index deb2ab3403..90d624b03a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -45,6 +45,7 @@ #include #include +#include #include "rtsp-client.h" #include "rtsp-sdp.h" @@ -115,17 +116,27 @@ enum { SIGNAL_CLOSED, SIGNAL_NEW_SESSION, + SIGNAL_PRE_OPTIONS_REQUEST, SIGNAL_OPTIONS_REQUEST, + SIGNAL_PRE_DESCRIBE_REQUEST, SIGNAL_DESCRIBE_REQUEST, + SIGNAL_PRE_SETUP_REQUEST, SIGNAL_SETUP_REQUEST, + SIGNAL_PRE_PLAY_REQUEST, SIGNAL_PLAY_REQUEST, + SIGNAL_PRE_PAUSE_REQUEST, SIGNAL_PAUSE_REQUEST, + SIGNAL_PRE_TEARDOWN_REQUEST, SIGNAL_TEARDOWN_REQUEST, + SIGNAL_PRE_SET_PARAMETER_REQUEST, SIGNAL_SET_PARAMETER_REQUEST, + SIGNAL_PRE_GET_PARAMETER_REQUEST, SIGNAL_GET_PARAMETER_REQUEST, SIGNAL_HANDLE_RESPONSE, SIGNAL_SEND_MESSAGE, + SIGNAL_PRE_ANNOUNCE_REQUEST, SIGNAL_ANNOUNCE_REQUEST, + SIGNAL_PRE_RECORD_REQUEST, SIGNAL_RECORD_REQUEST, SIGNAL_CHECK_REQUIREMENTS, SIGNAL_LAST @@ -157,6 +168,10 @@ static gchar *default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri); static void client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session, GstRTSPClient * client); +static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client, + GstRTSPContext * ctx); +static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint, + GValue * return_accu, const GValue * handler_return, gpointer data); G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT); @@ -181,6 +196,17 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) klass->params_get = default_params_get; klass->make_path_from_uri = default_make_path_from_uri; + klass->pre_options_request = default_pre_signal_handler; + klass->pre_describe_request = default_pre_signal_handler; + klass->pre_setup_request = default_pre_signal_handler; + klass->pre_play_request = default_pre_signal_handler; + klass->pre_pause_request = default_pre_signal_handler; + klass->pre_teardown_request = default_pre_signal_handler; + klass->pre_set_parameter_request = default_pre_signal_handler; + klass->pre_get_parameter_request = default_pre_signal_handler; + klass->pre_announce_request = default_pre_signal_handler; + klass->pre_record_request = default_pre_signal_handler; + g_object_class_install_property (gobject_class, PROP_SESSION_POOL, g_param_spec_object ("session-pool", "Session Pool", "The session pool to use for client session", @@ -208,48 +234,184 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION); + /** + * GstRTSPClient::pre-options-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST] = + g_signal_new ("pre-options-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_options_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] = g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-describe-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST] = + g_signal_new ("pre-describe-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_describe_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] = g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-setup-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST] = + g_signal_new ("pre-setup-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_setup_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] = g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-play-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST] = + g_signal_new ("pre-play-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_play_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] = g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-pause-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST] = + g_signal_new ("pre-pause-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_pause_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] = g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-teardown-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST] = + g_signal_new ("pre-teardown-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_teardown_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] = g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-set-parameter-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST] = + g_signal_new ("pre-set-parameter-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_set_parameter_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, + GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] = g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, set_parameter_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-get-parameter-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST] = + g_signal_new ("pre-get-parameter-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_get_parameter_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] = g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, @@ -274,12 +436,46 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass) send_message), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER); + /** + * GstRTSPClient::pre-announce-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST] = + g_signal_new ("pre-announce-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_announce_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] = g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT); + /** + * GstRTSPClient::pre-record-request: + * @client: a #GstRTSPClient + * @ctx: a #GstRTSPContext + * + * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success, + * otherwise an appropriate return code + * + * Since: 1.12 + */ + gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST] = + g_signal_new ("pre-record-request", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, + pre_record_request), pre_signal_accumulator, NULL, + g_cclosure_marshal_generic, GST_TYPE_RTSP_STATUS_CODE, 1, + GST_TYPE_RTSP_CONTEXT); + gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] = g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request), @@ -864,6 +1060,47 @@ default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri) return path; } +/* Default signal handler function for all "pre-command" signals, like + * pre-options-request. It just returns the RTSP return code 200. + * Subclasses can override this to get another default behaviour. + */ +static GstRTSPStatusCode +default_pre_signal_handler (GstRTSPClient * client, GstRTSPContext * ctx) +{ + GST_LOG_OBJECT (client, "returning GST_RTSP_STS_OK"); + return GST_RTSP_STS_OK; +} + +/* The pre-signal accumulator function checks the return value of the signal + * handlers. If any of them returns an RTSP status code that does not start + * with 2 it will return FALSE, no more signal handlers will be called, and + * this last RTSP status code will be the result of the signal emission. + */ +static gboolean +pre_signal_accumulator (GSignalInvocationHint * ihint, GValue * return_accu, + const GValue * handler_return, gpointer data) +{ + GstRTSPStatusCode handler_value = g_value_get_enum (handler_return); + GstRTSPStatusCode accumulated_value = g_value_get_enum (return_accu); + + if (handler_value < 200 || handler_value > 299) { + GST_DEBUG ("handler_value : %d, returning FALSE", handler_value); + g_value_set_enum (return_accu, handler_value); + return FALSE; + } + + /* the accumulated value is initiated to 0 by GLib. if current handler value is + * bigger then use that instead + * + * FIXME: Should we prioritize the 2xx codes in a smarter way? + * Like, "201 Created" > "250 Low On Storage Space" > "200 OK"? + */ + if (handler_value > accumulated_value) + g_value_set_enum (return_accu, handler_value); + + return TRUE; +} + static gboolean handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) { @@ -875,6 +1112,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path; gint matched; gboolean keep_session; + GstRTSPStatusCode sig_result; if (!ctx->session) goto no_session; @@ -900,6 +1138,12 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST], + 0, ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + /* we emit the signal before closing the connection */ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST], 0, ctx); @@ -952,6 +1196,13 @@ no_aggregate: g_free (path); return FALSE; } +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); + return FALSE; + } } static GstRTSPResult @@ -980,6 +1231,14 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; guint8 *data; guint size; + GstRTSPStatusCode sig_result; + + g_signal_emit (client, + gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST], 0, ctx, + &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } res = gst_rtsp_message_get_body (ctx->request, &data, &size); if (res != GST_RTSP_OK) @@ -1003,6 +1262,13 @@ handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx) return TRUE; /* ERRORS */ +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); + return FALSE; + } bad_request: { GST_ERROR ("client %p: bad request", client); @@ -1017,6 +1283,14 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPResult res; guint8 *data; guint size; + GstRTSPStatusCode sig_result; + + g_signal_emit (client, + gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST], 0, ctx, + &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } res = gst_rtsp_message_get_body (ctx->request, &data, &size); if (res != GST_RTSP_OK) @@ -1040,6 +1314,13 @@ handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx) return TRUE; /* ERRORS */ +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); + return FALSE; + } bad_request: { GST_ERROR ("client %p: bad request", client); @@ -1059,6 +1340,7 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPState rtspstate; gchar *path; gint matched; + GstRTSPStatusCode sig_result; guint i, n; if (!(session = ctx->session)) @@ -1092,6 +1374,12 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia); /* the session state must be playing or recording */ if (rtspstate != GST_RTSP_STATE_PLAYING && @@ -1143,6 +1431,13 @@ no_aggregate: g_free (path); return FALSE; } +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); + return FALSE; + } invalid_state: { GST_ERROR ("client %p: not PLAYING or RECORDING", client); @@ -1197,6 +1492,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT; gchar *path, *rtpinfo; gint matched; + GstRTSPStatusCode sig_result; if (!(session = ctx->session)) goto no_session; @@ -1220,6 +1516,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_PLAY)) goto unsupported_mode; @@ -1306,6 +1608,13 @@ no_aggregate: g_free (path); return FALSE; } +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); + return FALSE; + } invalid_state: { GST_ERROR ("client %p: not PLAYING or READY", client); @@ -1851,6 +2160,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *control = NULL; gint matched; gboolean new_session = FALSE; + GstRTSPStatusCode sig_result; if (!ctx->uri) goto no_uri; @@ -1923,6 +2233,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->stream = stream; ctx->media = media; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (session == NULL) { /* create a session if this fails we probably reached our session limit or * something. */ @@ -2089,6 +2405,14 @@ stream_not_found: g_object_unref (media); goto cleanup_session; } +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); + g_object_unref (media); + goto cleanup_path; + } service_unavailable: { GST_ERROR ("client %p: can't create session", client); @@ -2217,12 +2541,19 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *str; GstRTSPMedia *media; GstRTSPClientClass *klass; + GstRTSPStatusCode sig_result; klass = GST_RTSP_CLIENT_GET_CLASS (client); if (!ctx->uri) goto no_uri; + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST], + 0, ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + /* check what kind of format is accepted, we don't really do anything with it * and always return SDP for now. */ for (i = 0;; i++) { @@ -2286,6 +2617,13 @@ handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx) return TRUE; /* ERRORS */ +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); + return FALSE; + } no_uri: { GST_ERROR ("client %p: no uri", client); @@ -2380,6 +2718,7 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) gchar *path, *cont = NULL; guint8 *data; guint size; + GstRTSPStatusCode sig_result; klass = GST_RTSP_CLIENT_GET_CLASS (client); @@ -2417,6 +2756,14 @@ handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx) if (!(media = find_media (client, ctx, path, NULL))) goto no_media; + ctx->media = media; + + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST], + 0, ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_RECORD)) goto unsupported_mode; @@ -2487,6 +2834,14 @@ no_media: gst_sdp_message_free (sdp); return FALSE; } +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); + gst_sdp_message_free (sdp); + return FALSE; + } unsupported_mode: { GST_ERROR ("client %p: media does not support ANNOUNCE", client); @@ -2518,6 +2873,7 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) GstRTSPState rtspstate; gchar *path; gint matched; + GstRTSPStatusCode sig_result; if (!(session = ctx->session)) goto no_session; @@ -2541,6 +2897,12 @@ handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx) ctx->sessmedia = sessmedia; ctx->media = media = gst_rtsp_session_media_get_media (sessmedia); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + if (!(gst_rtsp_media_get_transport_mode (media) & GST_RTSP_TRANSPORT_MODE_RECORD)) goto unsupported_mode; @@ -2596,6 +2958,13 @@ no_aggregate: g_free (path); return FALSE; } +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); + return FALSE; + } unsupported_mode: { GST_ERROR ("client %p: media does not support RECORD", client); @@ -2622,6 +2991,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) { GstRTSPMethod options; gchar *str; + GstRTSPStatusCode sig_result; options = GST_RTSP_DESCRIBE | GST_RTSP_OPTIONS | @@ -2639,12 +3009,28 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx) gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str); g_free (str); + g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST], 0, + ctx, &sig_result); + if (sig_result != GST_RTSP_STS_OK) { + goto sig_failed; + } + send_message (client, ctx, ctx->response, FALSE); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST], 0, ctx); return TRUE; + +/* ERRORS */ +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); + gst_rtsp_message_free (ctx->response); + return FALSE; + } } /* remove duplicate and trailing '/' */ diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 766e97dc95..3daef070d2 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -128,8 +128,19 @@ struct _GstRTSPClientClass { void (*record_request) (GstRTSPClient *client, GstRTSPContext *ctx); gchar* (*check_requirements) (GstRTSPClient *client, GstRTSPContext *ctx, gchar ** arr); + GstRTSPStatusCode (*pre_options_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_describe_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_setup_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_play_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_pause_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_teardown_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_set_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_get_parameter_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_announce_request) (GstRTSPClient *client, GstRTSPContext *ctx); + GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx); + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE-6]; + gpointer _gst_reserved[GST_PADDING_LARGE-16]; }; GType gst_rtsp_client_get_type (void);