rtsp-client: allow application to decide what requirements are supported

Add "check-requirements" signal and vfunc to allow application
(and subclasses) to check the requirements.

Based on patch from Hyunjun Ko <zzoon.ko@samsung.com>

https://bugzilla.gnome.org/show_bug.cgi?id=749417
This commit is contained in:
Ognyan Tonchev 2015-06-18 13:12:04 +02:00 committed by Tim-Philipp Müller
parent d59c7981cc
commit 8922afb88d
3 changed files with 187 additions and 12 deletions

View file

@ -127,6 +127,7 @@ enum
SIGNAL_SEND_MESSAGE, SIGNAL_SEND_MESSAGE,
SIGNAL_ANNOUNCE_REQUEST, SIGNAL_ANNOUNCE_REQUEST,
SIGNAL_RECORD_REQUEST, SIGNAL_RECORD_REQUEST,
SIGNAL_CHECK_REQUIREMENTS,
SIGNAL_LAST SIGNAL_LAST
}; };
@ -285,6 +286,24 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass)
NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
GST_TYPE_RTSP_CONTEXT); GST_TYPE_RTSP_CONTEXT);
/**
* GstRTSPClient::check-requirements:
* @client: a #GstRTSPClient
* @ctx: a #GstRTSPContext
* @arr: a NULL-terminated array of strings
*
* Returns: a newly allocated string with comma-separated list of
* unsupported options. An empty string must be returned if
* all options are supported.
*
* Since: 1.6
*/
gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS] =
g_signal_new ("check-requirements", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
check_requirements), NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_STRING, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_STRV);
tunnels = tunnels =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
g_mutex_init (&tunnels_lock); g_mutex_init (&tunnels_lock);
@ -2602,25 +2621,29 @@ client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session,
g_mutex_unlock (&priv->lock); g_mutex_unlock (&priv->lock);
} }
/* Returns TRUE if there are no Require headers, otherwise returns FALSE /* Check for Require headers. Returns TRUE if there are no Require headers,
* and also returns a newly-allocated string of (comma-separated) unsupported * otherwise lets the application decide which headers are supported.
* options in the unsupported_reqs variable . * By default all headers are unsupported.
* If there are unsupported options, FALSE will be returned together with
* a newly-allocated string of (comma-separated) unsupported options in
* the unsupported_reqs variable.
* *
* There may be multiple Require headers, but we must send one single * There may be multiple Require headers, but we must send one single
* Unsupported header with all the unsupported options as response. If * Unsupported header with all the unsupported options as response. If
* an incoming Require header contained a comma-separated list of options * an incoming Require header contained a comma-separated list of options
* GstRtspConnection will already have split that list up into multiple * GstRtspConnection will already have split that list up into multiple
* headers. * headers.
*
* TODO: allow the application to decide what features are supported
*/ */
static gboolean static gboolean
check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs) check_request_requirements (GstRTSPContext * ctx, gchar ** unsupported_reqs)
{ {
GstRTSPResult res; GstRTSPResult res;
GPtrArray *arr = NULL; GPtrArray *arr = NULL;
GstRTSPMessage *msg = ctx->request;
gchar *reqs = NULL; gchar *reqs = NULL;
gint i; gint i;
gchar *sig_result = NULL;
gboolean result = TRUE;
i = 0; i = 0;
do { do {
@ -2643,12 +2666,28 @@ check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs)
/* otherwise we've now processed at all the Require headers */ /* otherwise we've now processed at all the Require headers */
g_ptr_array_add (arr, NULL); g_ptr_array_add (arr, NULL);
/* for now we don't commit to supporting anything, so will just report g_signal_emit (ctx->client,
* all of the required options as unsupported */ gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS], 0, ctx,
*unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata); (gchar **) arr->pdata, &sig_result);
if (sig_result == NULL) {
/* no supported options, just report all of the required ones as
* unsupported */
*unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata);
result = FALSE;
goto done;
}
if (strlen (sig_result) == 0)
g_free (sig_result);
else {
*unsupported_reqs = sig_result;
result = FALSE;
}
done:
g_ptr_array_unref (arr); g_ptr_array_unref (arr);
return FALSE; return result;
} }
static void static void
@ -2752,7 +2791,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
goto not_authorized; goto not_authorized;
/* handle any 'Require' headers */ /* handle any 'Require' headers */
if (!check_request_requirements (ctx->request, &unsupported_reqs)) if (!check_request_requirements (ctx, &unsupported_reqs))
goto unsupported_requirement; goto unsupported_requirement;
/* the backlog must be unlimited while processing requests. /* the backlog must be unlimited while processing requests.

View file

@ -126,9 +126,10 @@ struct _GstRTSPClientClass {
void (*announce_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*announce_request) (GstRTSPClient *client, GstRTSPContext *ctx);
void (*record_request) (GstRTSPClient *client, GstRTSPContext *ctx); void (*record_request) (GstRTSPClient *client, GstRTSPContext *ctx);
gchar* (*check_requirements) (GstRTSPClient *client, GstRTSPContext *ctx, gchar ** arr);
/*< private >*/ /*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE-5]; gpointer _gst_reserved[GST_PADDING_LARGE-6];
}; };
GType gst_rtsp_client_get_type (void); GType gst_rtsp_client_get_type (void);

View file

@ -24,6 +24,7 @@
static gchar * session_id; static gchar * session_id;
static gint cseq; static gint cseq;
static guint expected_session_timeout = 60; static guint expected_session_timeout = 60;
static const gchar *expected_unsupported_header;
static gboolean static gboolean
test_response_200 (GstRTSPClient * client, GstRTSPMessage * response, test_response_200 (GstRTSPClient * client, GstRTSPMessage * response,
@ -109,6 +110,31 @@ test_response_454 (GstRTSPClient * client, GstRTSPMessage * response,
return TRUE; return TRUE;
} }
static gboolean
test_response_551 (GstRTSPClient * client, GstRTSPMessage * response,
gboolean close, gpointer user_data)
{
GstRTSPStatusCode code;
const gchar *reason;
GstRTSPVersion version;
gchar *options;
fail_unless (gst_rtsp_message_get_type (response) ==
GST_RTSP_MESSAGE_RESPONSE);
fail_unless (gst_rtsp_message_parse_response (response, &code, &reason,
&version)
== GST_RTSP_OK);
fail_unless (code == GST_RTSP_STS_OPTION_NOT_SUPPORTED);
fail_unless (g_str_equal (reason, "Option not supported"));
fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_UNSUPPORTED,
&options, 0) == GST_RTSP_OK);
fail_unless (!g_strcmp0 (expected_unsupported_header, options));
fail_unless (version == GST_RTSP_VERSION_1_0);
return TRUE;
}
static GstRTSPClient * static GstRTSPClient *
setup_client (const gchar * launch_line) setup_client (const gchar * launch_line)
{ {
@ -151,6 +177,114 @@ teardown_client (GstRTSPClient * client)
g_object_unref (client); g_object_unref (client);
} }
static gchar*
check_requirements_cb (GstRTSPClient * client, GstRTSPContext * ctx,
gchar ** req, gpointer user_data)
{
int index = 0;
GString *result = g_string_new ("");
while (req[index] != NULL) {
if (g_strcmp0 (req[index], "test-requirements")) {
if (result->len > 0)
g_string_append (result, ", ");
g_string_append (result, req[index]);
}
index++;
}
return g_string_free (result, FALSE);
}
GST_START_TEST (test_require)
{
GstRTSPClient *client;
GstRTSPMessage request = { 0, };
gchar *str;
client = gst_rtsp_client_new ();
/* require header without handler */
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("test-not-supported1");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
expected_unsupported_header = "test-not-supported1";
gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL);
fail_unless (gst_rtsp_client_handle_message (client,
&request) == GST_RTSP_OK);
gst_rtsp_message_unset (&request);
g_signal_connect (G_OBJECT (client), "check-requirements",
G_CALLBACK (check_requirements_cb), NULL);
/* one supported option */
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("test-requirements");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL);
fail_unless (gst_rtsp_client_handle_message (client,
&request) == GST_RTSP_OK);
gst_rtsp_message_unset (&request);
/* unsupported option */
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("test-not-supported1");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
expected_unsupported_header = "test-not-supported1";
gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL);
fail_unless (gst_rtsp_client_handle_message (client,
&request) == GST_RTSP_OK);
gst_rtsp_message_unset (&request);
/* more than one unsupported options */
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("test-not-supported1");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
str = g_strdup_printf ("test-not-supported2");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
expected_unsupported_header = "test-not-supported1, test-not-supported2";
gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL);
fail_unless (gst_rtsp_client_handle_message (client,
&request) == GST_RTSP_OK);
gst_rtsp_message_unset (&request);
/* supported and unsupported together */
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("test-not-supported1");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
str = g_strdup_printf ("test-requirements");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
str = g_strdup_printf ("test-not-supported2");
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str);
g_free (str);
expected_unsupported_header = "test-not-supported1, test-not-supported2";
gst_rtsp_client_set_send_func (client, test_response_551, NULL, NULL);
fail_unless (gst_rtsp_client_handle_message (client,
&request) == GST_RTSP_OK);
gst_rtsp_message_unset (&request);
g_object_unref (client);
}
GST_END_TEST;
GST_START_TEST (test_request) GST_START_TEST (test_request)
{ {
GstRTSPClient *client; GstRTSPClient *client;
@ -907,6 +1041,7 @@ rtspclient_suite (void)
suite_add_tcase (s, tc); suite_add_tcase (s, tc);
tcase_set_timeout (tc, 20); tcase_set_timeout (tc, 20);
tcase_add_test (tc, test_require);
tcase_add_test (tc, test_request); tcase_add_test (tc, test_request);
tcase_add_test (tc, test_options); tcase_add_test (tc, test_options);
tcase_add_test (tc, test_describe); tcase_add_test (tc, test_describe);