rtspsrc set parameter request

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

rtspsrc set parameter request

wilson1994
Hi,

I set up 2 applications: one server using the gst-rtsp-server library to
send a stream over rtsp, and one client application using rtspsrc to receive
the stream.

I would like the client to be able to set parameters in the server using the
rtsp SET_PARAMETER method. I see that rtspsrc has a "set-parameter" signal,
but I don't understand how I can implement this in my C project.

Does anyone have some example code that he/she can share, or provide me
information so I can better understand how to implement this?

Thank you in advance!

Kind regards,

Thomas



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: rtspsrc set parameter request

wilson1994
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/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel