mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
Client: keep a ref to the session
Don't just keep a weak ref to the session objects but use a hard ref. We will be notified when a session is removed from the pool (expired) with the new session-removed signal. Don't automatically close the RTSP connection when all the sessions of a client are removed, a client can continue to operate and it can create a new session if it wants. If you want to remove the client from the server, you have to use gst_rtsp_server_client_filter() now. Based on patch from Ognyan Tonchev <ognyan.tonchev at axis.com> See https://bugzilla.gnome.org/show_bug.cgi?id=732226
This commit is contained in:
parent
964ca3c988
commit
fe081e7301
1 changed files with 65 additions and 81 deletions
|
@ -71,6 +71,7 @@ struct _GstRTSPClientPrivate
|
||||||
GDestroyNotify send_notify; /* protected by send_lock */
|
GDestroyNotify send_notify; /* protected by send_lock */
|
||||||
|
|
||||||
GstRTSPSessionPool *session_pool;
|
GstRTSPSessionPool *session_pool;
|
||||||
|
gulong session_removed_id;
|
||||||
GstRTSPMountPoints *mount_points;
|
GstRTSPMountPoints *mount_points;
|
||||||
GstRTSPAuth *auth;
|
GstRTSPAuth *auth;
|
||||||
GstRTSPThreadPool *thread_pool;
|
GstRTSPThreadPool *thread_pool;
|
||||||
|
@ -131,8 +132,6 @@ static void gst_rtsp_client_set_property (GObject * object, guint propid,
|
||||||
static void gst_rtsp_client_finalize (GObject * obj);
|
static void gst_rtsp_client_finalize (GObject * obj);
|
||||||
|
|
||||||
static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
|
static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
|
||||||
static void client_session_finalized (GstRTSPClient * client,
|
|
||||||
GstRTSPSession * session);
|
|
||||||
static void unlink_session_transports (GstRTSPClient * client,
|
static void unlink_session_transports (GstRTSPClient * client,
|
||||||
GstRTSPSession * session, GstRTSPSessionMedia * sessmedia);
|
GstRTSPSession * session, GstRTSPSessionMedia * sessmedia);
|
||||||
static gboolean default_configure_client_media (GstRTSPClient * client,
|
static gboolean default_configure_client_media (GstRTSPClient * client,
|
||||||
|
@ -281,7 +280,7 @@ gst_rtsp_client_init (GstRTSPClient * client)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstRTSPFilterResult
|
static GstRTSPFilterResult
|
||||||
filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
|
filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
|
GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
|
||||||
|
@ -293,66 +292,46 @@ filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
|
||||||
return GST_RTSP_FILTER_REMOVE;
|
return GST_RTSP_FILTER_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
|
|
||||||
{
|
|
||||||
/* unlink all media managed in this session */
|
|
||||||
gst_rtsp_session_filter (session, filter_session, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
|
client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
|
||||||
{
|
{
|
||||||
GstRTSPClientPrivate *priv = client->priv;
|
GstRTSPClientPrivate *priv = client->priv;
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
for (walk = priv->sessions; walk; walk = g_list_next (walk)) {
|
/* we already know about this session */
|
||||||
GstRTSPSession *msession = (GstRTSPSession *) walk->data;
|
if (g_list_find (priv->sessions, session) != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
/* we already know about this session */
|
GST_INFO ("watching session %p", session);
|
||||||
if (msession == session)
|
priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session,
|
||||||
|
GList * link)
|
||||||
|
{
|
||||||
|
GstRTSPClientPrivate *priv = client->priv;
|
||||||
|
|
||||||
|
GST_INFO ("client %p: unwatch session %p", client, session);
|
||||||
|
|
||||||
|
if (link == NULL) {
|
||||||
|
link = g_list_find (priv->sessions, session);
|
||||||
|
if (link == NULL)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_INFO ("watching session %p", session);
|
/* unlink all media managed in this session */
|
||||||
|
gst_rtsp_session_filter (session, filter_session_media, client);
|
||||||
|
|
||||||
g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
|
/* remove the session */
|
||||||
client);
|
priv->sessions = g_list_delete_link (priv->sessions, link);
|
||||||
priv->sessions = g_list_prepend (priv->sessions, session);
|
g_object_unref (session);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstRTSPFilterResult
|
||||||
client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session)
|
cleanup_session (GstRTSPClient * client, GstRTSPSession * sess,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GstRTSPClientPrivate *priv = client->priv;
|
return GST_RTSP_FILTER_REMOVE;
|
||||||
|
|
||||||
GST_INFO ("unwatching session %p", session);
|
|
||||||
|
|
||||||
g_object_weak_unref (G_OBJECT (session),
|
|
||||||
(GWeakNotify) client_session_finalized, client);
|
|
||||||
priv->sessions = g_list_remove (priv->sessions, session);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
client_cleanup_session (GstRTSPClient * client, GstRTSPSession * session)
|
|
||||||
{
|
|
||||||
g_object_weak_unref (G_OBJECT (session),
|
|
||||||
(GWeakNotify) client_session_finalized, client);
|
|
||||||
client_unlink_session (client, session);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
client_cleanup_sessions (GstRTSPClient * client)
|
|
||||||
{
|
|
||||||
GstRTSPClientPrivate *priv = client->priv;
|
|
||||||
GList *sessions;
|
|
||||||
|
|
||||||
/* remove weak-ref from sessions */
|
|
||||||
for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) {
|
|
||||||
client_cleanup_session (client, (GstRTSPSession *) sessions->data);
|
|
||||||
}
|
|
||||||
g_list_free (priv->sessions);
|
|
||||||
priv->sessions = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A client is finalized when the connection is broken */
|
/* A client is finalized when the connection is broken */
|
||||||
|
@ -374,12 +353,14 @@ gst_rtsp_client_finalize (GObject * obj)
|
||||||
if (priv->watch_context)
|
if (priv->watch_context)
|
||||||
g_main_context_unref (priv->watch_context);
|
g_main_context_unref (priv->watch_context);
|
||||||
|
|
||||||
client_cleanup_sessions (client);
|
gst_rtsp_client_session_filter (client, cleanup_session, NULL);
|
||||||
|
|
||||||
if (priv->connection)
|
if (priv->connection)
|
||||||
gst_rtsp_connection_free (priv->connection);
|
gst_rtsp_connection_free (priv->connection);
|
||||||
if (priv->session_pool)
|
if (priv->session_pool) {
|
||||||
|
g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id);
|
||||||
g_object_unref (priv->session_pool);
|
g_object_unref (priv->session_pool);
|
||||||
|
}
|
||||||
if (priv->mount_points)
|
if (priv->mount_points)
|
||||||
g_object_unref (priv->mount_points);
|
g_object_unref (priv->mount_points);
|
||||||
if (priv->auth)
|
if (priv->auth)
|
||||||
|
@ -797,15 +778,16 @@ close_connection (GstRTSPClient * client)
|
||||||
|
|
||||||
GST_DEBUG ("client %p: closing connection", client);
|
GST_DEBUG ("client %p: closing connection", client);
|
||||||
|
|
||||||
if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
|
if (priv->connection) {
|
||||||
g_mutex_lock (&tunnels_lock);
|
if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
|
||||||
/* remove from tunnelids */
|
g_mutex_lock (&tunnels_lock);
|
||||||
g_hash_table_remove (tunnels, tunnelid);
|
/* remove from tunnelids */
|
||||||
g_mutex_unlock (&tunnels_lock);
|
g_hash_table_remove (tunnels, tunnelid);
|
||||||
|
g_mutex_unlock (&tunnels_lock);
|
||||||
|
}
|
||||||
|
gst_rtsp_connection_close (priv->connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_rtsp_connection_close (priv->connection);
|
|
||||||
|
|
||||||
/* connection is now closed, destroy the watch which will also cause the
|
/* connection is now closed, destroy the watch which will also cause the
|
||||||
* closed signal to be emitted */
|
* closed signal to be emitted */
|
||||||
if (priv->watch) {
|
if (priv->watch) {
|
||||||
|
@ -839,6 +821,7 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
GstRTSPStatusCode code;
|
GstRTSPStatusCode code;
|
||||||
gchar *path;
|
gchar *path;
|
||||||
gint matched;
|
gint matched;
|
||||||
|
gboolean keep_session;
|
||||||
|
|
||||||
if (!ctx->session)
|
if (!ctx->session)
|
||||||
goto no_session;
|
goto no_session;
|
||||||
|
@ -875,9 +858,6 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
/* unlink the all TCP callbacks */
|
/* unlink the all TCP callbacks */
|
||||||
unlink_session_transports (client, session, sessmedia);
|
unlink_session_transports (client, session, sessmedia);
|
||||||
|
|
||||||
/* remove the session from the watched sessions */
|
|
||||||
client_unwatch_session (client, session);
|
|
||||||
|
|
||||||
gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
|
gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
|
||||||
|
|
||||||
/* allow messages again so that we can send the reply */
|
/* allow messages again so that we can send the reply */
|
||||||
|
@ -885,10 +865,8 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
|
|
||||||
/* unmanage the media in the session, returns false if all media session
|
/* unmanage the media in the session, returns false if all media session
|
||||||
* are torn down. */
|
* are torn down. */
|
||||||
if (!gst_rtsp_session_release_media (session, sessmedia)) {
|
keep_session = gst_rtsp_session_release_media (session, sessmedia);
|
||||||
/* remove the session */
|
|
||||||
gst_rtsp_session_pool_remove (priv->session_pool, session);
|
|
||||||
}
|
|
||||||
/* construct the response now */
|
/* construct the response now */
|
||||||
code = GST_RTSP_STS_OK;
|
code = GST_RTSP_STS_OK;
|
||||||
gst_rtsp_message_init_response (ctx->response, code,
|
gst_rtsp_message_init_response (ctx->response, code,
|
||||||
|
@ -896,6 +874,11 @@ handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
|
|
||||||
send_message (client, ctx, ctx->response, TRUE);
|
send_message (client, ctx, ctx->response, TRUE);
|
||||||
|
|
||||||
|
if (!keep_session) {
|
||||||
|
/* remove the session */
|
||||||
|
gst_rtsp_session_pool_remove (priv->session_pool, session);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -2247,22 +2230,13 @@ sanitize_uri (GstRTSPUrl * uri)
|
||||||
*d = '\0';
|
*d = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* is called when the session is removed from its session pool. */
|
||||||
static void
|
static void
|
||||||
client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
|
client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session,
|
||||||
|
GstRTSPClient * client)
|
||||||
{
|
{
|
||||||
GstRTSPClientPrivate *priv = client->priv;
|
GST_INFO ("client %p: session %p removed", client, session);
|
||||||
|
client_unwatch_session (client, session, NULL);
|
||||||
GST_INFO ("client %p: session %p finished", client, session);
|
|
||||||
|
|
||||||
/* unlink all media managed in this session */
|
|
||||||
client_unlink_session (client, session);
|
|
||||||
|
|
||||||
/* remove the session */
|
|
||||||
if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
|
|
||||||
GST_INFO ("client %p: all sessions finalized, close the connection",
|
|
||||||
client);
|
|
||||||
close_connection (client);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns TRUE if there are no Require headers, otherwise returns FALSE
|
/* Returns TRUE if there are no Require headers, otherwise returns FALSE
|
||||||
|
@ -2656,8 +2630,17 @@ gst_rtsp_client_set_session_pool (GstRTSPClient * client,
|
||||||
g_mutex_lock (&priv->lock);
|
g_mutex_lock (&priv->lock);
|
||||||
old = priv->session_pool;
|
old = priv->session_pool;
|
||||||
priv->session_pool = pool;
|
priv->session_pool = pool;
|
||||||
|
|
||||||
|
if (priv->session_removed_id)
|
||||||
|
g_signal_handler_disconnect (old, priv->session_removed_id);
|
||||||
|
if (pool)
|
||||||
|
priv->session_removed_id = g_signal_connect (pool, "session-removed",
|
||||||
|
G_CALLBACK (client_session_removed), client);
|
||||||
|
else
|
||||||
|
priv->session_removed_id = 0;
|
||||||
g_mutex_unlock (&priv->lock);
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
|
/* FIXME, should remove all sessions from the old pool for this client */
|
||||||
if (old)
|
if (old)
|
||||||
g_object_unref (old);
|
g_object_unref (old);
|
||||||
}
|
}
|
||||||
|
@ -3112,6 +3095,7 @@ message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
|
||||||
GstRTSPClientPrivate *priv = client->priv;
|
GstRTSPClientPrivate *priv = client->priv;
|
||||||
|
|
||||||
if (priv->close_seq && priv->close_seq == cseq) {
|
if (priv->close_seq && priv->close_seq == cseq) {
|
||||||
|
GST_INFO ("client %p: send close message", client);
|
||||||
priv->close_seq = 0;
|
priv->close_seq = 0;
|
||||||
close_connection (client);
|
close_connection (client);
|
||||||
}
|
}
|
||||||
|
@ -3459,7 +3443,7 @@ gst_rtsp_client_session_filter (GstRTSPClient * client,
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case GST_RTSP_FILTER_REMOVE:
|
case GST_RTSP_FILTER_REMOVE:
|
||||||
/* stop watching the session and pretent it went away */
|
/* stop watching the session and pretent it went away */
|
||||||
client_cleanup_session (client, sess);
|
client_unwatch_session (client, sess, walk);
|
||||||
break;
|
break;
|
||||||
case GST_RTSP_FILTER_REF:
|
case GST_RTSP_FILTER_REF:
|
||||||
result = g_list_prepend (result, g_object_ref (sess));
|
result = g_list_prepend (result, g_object_ref (sess));
|
||||||
|
|
Loading…
Reference in a new issue