rtspsrc set parameter request
wilson1994
thomas_bliss at hotmail.be
Fri Sep 20 09:36:32 UTC 2019
To anyone wanting to implement get- and set- parameter requests, after a long
time going through the source code I have found the way to do it. Here is an
explanation:
First of all, get- and set-parameter has only been implemented since august
2018 (see link
<https://gstreamer-bugs.narkive.com/1ZFqXqdw/bug-792131-new-rtspsrc-add-an-action-signal-to-send-set-parameter>
), so you will need one of the latest version of gstreamer (I got it working
on 1.16.0)
GET-PARAMETER
I'll start with GET-PARAMETER, as it's more complex as the server will also
have to send the right response.
Client Side
rtspsrc has the "get-parameter" action signal to send a get-parameter
request. The function looks like this:
get_parameter_callback (GstElement rtspsrc,
gchararray parameter_name,
gchararray content_type,
GstPromise promise,
gpointer udata)
So everything we need is a pointer to the rtspsrc element, a string
containing the name, a string containing the content type (can be NULL), and
a pointer to the promise. The promise is an object that will hold
information about the response: if you got a response, or if it's expired,
timed out, ... and also the response itself. When you send a get-parameter
request through the action signal, you will want to block on the promise
until you received a reply, and afterwards you can read the reply in the
promise.
So the code for setting up the get-parameter looks like this:
int get_parameter(char name[8]) {
char *get_body;
char get_name[16];
char get_value[16];
// construct promise which we can read out later
GstPromise *promise = gst_promise_new();
// send action signal to send GET-PARAMETER request
g_signal_emit_by_name(rtspsrc, "get_parameter", name, NULL, promise);
// wait until response is received
GstPromiseResult result = gst_promise_wait(promise);
if (result == GST_PROMISE_RESULT_REPLIED) {
const GstStructure *reply = gst_promise_get_reply(promise);
// the response will be in the "body" part of GstStructure
get_body = gst_structure_get_string(reply, "body");
sscanf(get_body, "%s %s\n", get_name, get_value);
g_print("%s is %s \n", get_name, get_value);
}
else {
g_print("wait promise failed, code: %d \n", result);
}
}
Server Side
On server side (with gst-rtsp-server) we will need the specify how the
server needs to respond to requests.
Intuitively you would want to check the "get-parameter-request" signal of
GstRTSPClient object, but this callback is called /after/ the server has
already handled the request and sent a response, and the standard response
to a get-parameter request which the server doesn't understand (which
actually is any request), it will send an error response "Parameter not
understood", so this is quite useless.
Therefore you will need to find a way to change how the server handles
requests: when the server receives a get-parameter request, it will execute
a function "params_get", to initialize a response, which is actually a
function pointer in the GstRTSPClient structure. So we need to change the
function pointer to point to our own function to create a response. You can
do this by acquiring the GstRTSPClientClass object, and then setting the
function pointer to our own function. For this you need access to the
GstRTSPClient object, which you can acquire in the callback of the
"client-connected" signal of the server. so in the client-connected-callback
you can issue the following to get access to the GstRTSPClientClass:
static void client_connected_callback (GstRTSPServer * self, GstRTSPClient *
object, gpointer user_data)
{
GstRTSPClientClass *client_class = GST_RTSP_CLIENT_GET_CLASS (object);
// change function pointer to point to our own function
client_class->params_get = custom_params_get;
}
our own function will parse the request message from context, and depending
on the request will construct a response:
static GstRTSPResult custom_params_get (GstRTSPClient * client,
GstRTSPContext * ctx)
{
guint8 *request;
guint length = 0;
char parameter[32];
guint8 response[16];
gst_rtsp_message_get_body(ctx->request, &request, &length);
if (request != NULL) {
// extract parameter name from request
sscanf((char *)request, "%s\n", parameter);
if (strcmp(parameter, "requested_parameter:") == 0) {
// initialse a response
gst_rtsp_message_init_response(ctx->response, GST_RTSP_STS_OK,
NULL, ctx->request);
// add requested parameter and value to the body of the response
snprintf((char *)response, sizeof(response), "%s %d\n", name,
value_requested_parameter);
gst_rtsp_message_set_body(ctx->response, response,
sizeof(response));
}
}
return GST_RTSP_OK;
}
afterwards it will send send the response and your client will receive the
response in promise.
SET-PARAMETER
set parameter works almost the same:
Client Side
int MLXTOFset_parameter(char name[8], char value[8])
{
GstPromise *promise = gst_promise_new();
g_signal_emit_by_name(data.channel0.source, "set-parameter", name,
value, NULL, promise);
// you can check promise like you did in get-parameter to see if server
has accepted the request in the same way as above, but it's not necessary
return 0;
}
Server Side
To be complete, on server side you should also adapt the function pointer of
params_set so you can send the right response (if the server has accepted
the request), and you can do it the same way as in get-parameter, so I will
not repeat here. If you don't, the the server will always respond with
"Parameter not understood".
To receive the request, you have either already acquired it in your custom
function as explained in the previous paragraph, or you can simply use the
signal callback "set-parameter-request" of the GstRTSPClient object. In the
callback you have access to GstRTSPContext, from which you can access the
request message, so the callback would look like this:
static void set_parameter_request_callback (GstRTSPClient * self,
GstRTSPContext * ctx, gpointer user_data)
{
guint8 *request;
char name[32];
char value[32];
int value_int;
guint length = 0;
gst_rtsp_message_get_body(ctx->request, &request, &length);
sscanf((char *)request, "%s %s\n", name, value);
value_int = atoi(value);
if (strcmp(name, "parameter_to_be_set:") == 0) {
_parameter = value_int;
}
}
--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
More information about the gstreamer-devel
mailing list