From 33da3af265e1b3d5f658306080f99e69e99ce63d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 26 Nov 2012 17:20:39 +0100 Subject: [PATCH] client: make the client usable without a socket Make a method to let the client handle a message and a callback when the client wants us to send a response message back. This makes it possible to also use the client object without the sockets, which should make it easier to test. --- gst/rtsp-server/rtsp-client.c | 81 ++++++++++++++++++++++++++++++++++++------- gst/rtsp-server/rtsp-client.h | 31 +++++++++++++++++ 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 76c53da..87fea29 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -219,6 +219,9 @@ gst_rtsp_client_finalize (GObject * obj) if (client->watch) g_source_destroy ((GSource *) client->watch); + if (client->send_notify) + client->send_notify (client->send_data); + client_cleanup_sessions (client); gst_rtsp_connection_free (client->connection); @@ -323,13 +326,12 @@ send_response (GstRTSPClient * client, GstRTSPSession * session, gst_rtsp_message_dump (response); } - if (close) { + if (close) gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close"); - } - /* send the response and store the seq number so we can wait until it's - * written to the client to close the connection */ - gst_rtsp_watch_send_message (client->watch, response, close ? - &client->close_seq : NULL); + + if (client->send_func) + client->send_func (client, response, close, client->send_data); + gst_rtsp_message_unset (response); } @@ -496,9 +498,8 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client) gst_rtsp_message_take_body (&message, map_info.data, map_info.size); - /* FIXME, client->watch could have been finalized here, we need to keep an - * extra refcount to the watch. */ - gst_rtsp_watch_send_message (client->watch, &message, NULL); + if (client->send_func) + client->send_func (client, &message, FALSE, client->send_data); gst_rtsp_message_steal_body (&message, &data, &usize); gst_buffer_unmap (buffer, &map_info); @@ -1893,11 +1894,47 @@ gst_rtsp_client_get_auth (GstRTSPClient * client) return result; } -static GstRTSPResult -message_received (GstRTSPWatch * watch, GstRTSPMessage * message, - gpointer user_data) +/** + * gst_rtsp_client_set_send_func: + * @client: a #GstRTSPClient + * @func: a #GstRTSPClientSendFunc + * @user_data: user data passed to @func + * @notify: called when @user_data is no longer in use + * + * Set @func as the callback that will be called when a new message needs to be + * sent to the client. @user_data is passed to @func and @notify is called when + * @user_data is no longer in use. + */ +void +gst_rtsp_client_set_send_func (GstRTSPClient * client, + GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify) { - GstRTSPClient *client = GST_RTSP_CLIENT (user_data); + g_return_if_fail (GST_IS_RTSP_CLIENT (client)); + + g_mutex_lock (&client->lock); + client->send_func = func; + if (client->send_notify) + client->send_notify (client->send_data); + client->send_data = user_data; + client->send_notify = notify; + g_mutex_unlock (&client->lock); +} + +/** + * gst_rtsp_client_handle_message: + * @client: a #GstRTSPClient + * @message: an #GstRTSPMessage + * + * Let the client handle @message. + * + * Returns: a #GstRTSPResult. + */ +GstRTSPResult +gst_rtsp_client_handle_message (GstRTSPClient * client, + GstRTSPMessage * message) +{ + g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL); + g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); switch (message->type) { case GST_RTSP_MESSAGE_REQUEST: @@ -1915,6 +1952,23 @@ message_received (GstRTSPWatch * watch, GstRTSPMessage * message, } static GstRTSPResult +do_send_message (GstRTSPClient * client, GstRTSPMessage * message, + gboolean close, gpointer user_data) +{ + /* send the response and store the seq number so we can wait until it's + * written to the client to close the connection */ + return gst_rtsp_watch_send_message (client->watch, message, close ? + &client->close_seq : NULL); +} + +static GstRTSPResult +message_received (GstRTSPWatch * watch, GstRTSPMessage * message, + gpointer user_data) +{ + return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message); +} + +static GstRTSPResult message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data) { GstRTSPClient *client = GST_RTSP_CLIENT (user_data); @@ -2277,6 +2331,7 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context) /* create watch for the connection and attach */ client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, g_object_ref (client), (GDestroyNotify) client_watch_notify); + gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL); GST_INFO ("attaching to context %p", context); res = gst_rtsp_watch_attach (client->watch, context); diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 5cf7b14..ab3344b 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -73,6 +73,23 @@ struct _GstRTSPClientState { }; /** + * GstRTSPClientSendFunc: + * @client: a #GstRTSPClient + * @message: a #GstRTSPMessage + * @close: close the connection + * @user_data: user data when registering the callback + * + * This callback is called when @client wants to send @message. When @close is + * %TRUE, the connection should be closed when the message has been sent. + * + * Returns: %TRUE on success. + */ +typedef gboolean (*GstRTSPClientSendFunc) (GstRTSPClient *client, + GstRTSPMessage *message, + gboolean close, + gpointer user_data); + +/** * GstRTSPClient: * @lock: lock protecting the client object * @connection: the connection object handling the client request. @@ -81,6 +98,10 @@ struct _GstRTSPClientState { * @server_ip: ip address of the server * @is_ipv6: if we are IPv6 * @use_client_settings: whether to allow client transport settings for multicast + * @send_func: a #GstRTSPClientSendFunc called when an RTSP message needs to be + * sent to the client. + * @send_data: user data passed to @send_func + * @send_notify: notify called when @send_data is no longer used. * @session_pool: handle to the session pool used by the client. * @mount_points: handle to the mount points used by the client. * @auth: authorization object @@ -102,6 +123,10 @@ struct _GstRTSPClient { gboolean is_ipv6; gboolean use_client_settings; + GstRTSPClientSendFunc send_func; + gpointer send_data; + GDestroyNotify send_notify; + GstRTSPSessionPool *session_pool; GstRTSPMountPoints *mount_points; GstRTSPAuth *auth; @@ -150,6 +175,12 @@ gboolean gst_rtsp_client_get_use_client_settings (GstRTSPClient * c void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client); +void gst_rtsp_client_set_send_func (GstRTSPClient *client, + GstRTSPClientSendFunc func, + gpointer user_data, + GDestroyNotify notify); +GstRTSPResult gst_rtsp_client_handle_message (GstRTSPClient *client, + GstRTSPMessage *message); gboolean gst_rtsp_client_accept (GstRTSPClient *client, GSocket *socket, -- 2.7.4