2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 * SECTION:rtsp-session
21 * @short_description: An object to manage media
22 * @see_also: #GstRTSPSessionPool, #GstRTSPSessionMedia, #GstRTSPMedia
24 * The #GstRTSPSession is identified by an id, unique in the
25 * #GstRTSPSessionPool that created the session and manages media and its
28 * A #GstRTSPSession has a timeout that can be retrieved with
29 * gst_rtsp_session_get_timeout(). You can check if the sessions is expired with
30 * gst_rtsp_session_is_expired(). gst_rtsp_session_touch() will reset the
31 * expiration counter of the session.
33 * When a client configures a media with SETUP, a session will be created to
34 * keep track of the configuration of that media. With
35 * gst_rtsp_session_manage_media(), the media is added to the managed media
36 * in the session. With gst_rtsp_session_release_media() the media can be
37 * released again from the session. Managed media is identified in the sessions
38 * with a url. Use gst_rtsp_session_get_media() to get the media that matches
39 * (part of) the given url.
41 * The media in a session can be iterated with gst_rtsp_session_filter().
43 * Last reviewed on 2013-07-11 (1.0.0)
48 #include "rtsp-session.h"
50 #define GST_RTSP_SESSION_GET_PRIVATE(obj) \
51 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSessionPrivate))
53 struct _GstRTSPSessionPrivate
55 GMutex lock; /* protects everything but sessionid and create_time */
59 GTimeVal create_time; /* immutable */
68 #define DEFAULT_TIMEOUT 60
78 GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
79 #define GST_CAT_DEFAULT rtsp_session_debug
81 static void gst_rtsp_session_get_property (GObject * object, guint propid,
82 GValue * value, GParamSpec * pspec);
83 static void gst_rtsp_session_set_property (GObject * object, guint propid,
84 const GValue * value, GParamSpec * pspec);
85 static void gst_rtsp_session_finalize (GObject * obj);
87 G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT);
90 gst_rtsp_session_class_init (GstRTSPSessionClass * klass)
92 GObjectClass *gobject_class;
94 g_type_class_add_private (klass, sizeof (GstRTSPSessionPrivate));
96 gobject_class = G_OBJECT_CLASS (klass);
98 gobject_class->get_property = gst_rtsp_session_get_property;
99 gobject_class->set_property = gst_rtsp_session_set_property;
100 gobject_class->finalize = gst_rtsp_session_finalize;
102 g_object_class_install_property (gobject_class, PROP_SESSIONID,
103 g_param_spec_string ("sessionid", "Sessionid", "the session id",
104 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
105 G_PARAM_STATIC_STRINGS));
107 g_object_class_install_property (gobject_class, PROP_TIMEOUT,
108 g_param_spec_uint ("timeout", "timeout",
109 "the timeout of the session (0 = never)", 0, G_MAXUINT,
110 DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
112 GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
117 gst_rtsp_session_init (GstRTSPSession * session)
119 GstRTSPSessionPrivate *priv = GST_RTSP_SESSION_GET_PRIVATE (session);
121 session->priv = priv;
123 g_mutex_init (&priv->lock);
124 priv->timeout = DEFAULT_TIMEOUT;
125 g_get_current_time (&priv->create_time);
126 gst_rtsp_session_touch (session);
130 gst_rtsp_session_finalize (GObject * obj)
132 GstRTSPSession *session;
133 GstRTSPSessionPrivate *priv;
135 session = GST_RTSP_SESSION (obj);
136 priv = session->priv;
138 GST_INFO ("finalize session %p", session);
141 g_list_free_full (priv->medias, g_object_unref);
143 /* free session id */
144 g_free (priv->sessionid);
145 g_mutex_clear (&priv->lock);
147 G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj);
151 gst_rtsp_session_get_property (GObject * object, guint propid,
152 GValue * value, GParamSpec * pspec)
154 GstRTSPSession *session = GST_RTSP_SESSION (object);
155 GstRTSPSessionPrivate *priv = session->priv;
159 g_value_set_string (value, priv->sessionid);
162 g_value_set_uint (value, gst_rtsp_session_get_timeout (session));
165 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
170 gst_rtsp_session_set_property (GObject * object, guint propid,
171 const GValue * value, GParamSpec * pspec)
173 GstRTSPSession *session = GST_RTSP_SESSION (object);
174 GstRTSPSessionPrivate *priv = session->priv;
178 g_free (priv->sessionid);
179 priv->sessionid = g_value_dup_string (value);
182 gst_rtsp_session_set_timeout (session, g_value_get_uint (value));
185 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
190 * gst_rtsp_session_manage_media:
191 * @sess: a #GstRTSPSession
192 * @path: the path for the media
193 * @media: (transfer full): a #GstRTSPMedia
195 * Manage the media object @obj in @sess. @path will be used to retrieve this
196 * media from the session with gst_rtsp_session_get_media().
198 * Ownership is taken from @media.
200 * Returns: (transfer none): a new @GstRTSPSessionMedia object.
202 GstRTSPSessionMedia *
203 gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path,
204 GstRTSPMedia * media)
206 GstRTSPSessionPrivate *priv;
207 GstRTSPSessionMedia *result;
209 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
210 g_return_val_if_fail (path != NULL, NULL);
211 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
212 g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
213 GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
217 result = gst_rtsp_session_media_new (path, media);
219 g_mutex_lock (&priv->lock);
220 priv->medias = g_list_prepend (priv->medias, result);
221 g_mutex_unlock (&priv->lock);
223 GST_INFO ("manage new media %p in session %p", media, result);
229 * gst_rtsp_session_release_media:
230 * @sess: a #GstRTSPSession
231 * @media: a #GstRTSPMedia
233 * Release the managed @media in @sess, freeing the memory allocated by it.
235 * Returns: %TRUE if there are more media session left in @sess.
238 gst_rtsp_session_release_media (GstRTSPSession * sess,
239 GstRTSPSessionMedia * media)
241 GstRTSPSessionPrivate *priv;
245 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE);
246 g_return_val_if_fail (media != NULL, FALSE);
250 g_mutex_lock (&priv->lock);
251 find = g_list_find (priv->medias, media);
253 priv->medias = g_list_delete_link (priv->medias, find);
254 more = (priv->medias != NULL);
255 g_mutex_unlock (&priv->lock);
258 g_object_unref (media);
264 * gst_rtsp_session_get_media:
265 * @sess: a #GstRTSPSession
266 * @path: the path for the media
267 * @matched: (out): the amount of matched characters
269 * Get the session media for @path. @matched will contain the number of matched
270 * characters of @path.
272 * Returns: (transfer none): the configuration for @path in @sess.
274 GstRTSPSessionMedia *
275 gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path,
278 GstRTSPSessionPrivate *priv;
279 GstRTSPSessionMedia *result;
283 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
284 g_return_val_if_fail (path != NULL, NULL);
290 g_mutex_lock (&priv->lock);
291 for (walk = priv->medias; walk; walk = g_list_next (walk)) {
292 GstRTSPSessionMedia *test;
294 test = (GstRTSPSessionMedia *) walk->data;
296 /* find largest match */
297 if (gst_rtsp_session_media_matches (test, path, matched)) {
298 if (best < *matched) {
304 g_mutex_unlock (&priv->lock);
312 * gst_rtsp_session_filter:
313 * @sess: a #GstRTSPSession
314 * @func: (scope call) (allow-none): a callback
315 * @user_data: user data passed to @func
317 * Call @func for each media in @sess. The result value of @func determines
318 * what happens to the media. @func will be called with @sess
319 * locked so no further actions on @sess can be performed from @func.
321 * If @func returns #GST_RTSP_FILTER_REMOVE, the media will be removed from
324 * If @func returns #GST_RTSP_FILTER_KEEP, the media will remain in @sess.
326 * If @func returns #GST_RTSP_FILTER_REF, the media will remain in @sess but
327 * will also be added with an additional ref to the result #GList of this
330 * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for all media.
332 * Returns: (element-type GstRTSPSessionMedia) (transfer full): a GList with all
333 * media for which @func returned #GST_RTSP_FILTER_REF. After usage, each
334 * element in the #GList should be unreffed before the list is freed.
337 gst_rtsp_session_filter (GstRTSPSession * sess,
338 GstRTSPSessionFilterFunc func, gpointer user_data)
340 GstRTSPSessionPrivate *priv;
341 GList *result, *walk, *next;
343 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
349 g_mutex_lock (&priv->lock);
350 for (walk = priv->medias; walk; walk = next) {
351 GstRTSPSessionMedia *media = walk->data;
352 GstRTSPFilterResult res;
354 next = g_list_next (walk);
357 res = func (sess, media, user_data);
359 res = GST_RTSP_FILTER_REF;
362 case GST_RTSP_FILTER_REMOVE:
363 g_object_unref (media);
364 priv->medias = g_list_delete_link (priv->medias, walk);
366 case GST_RTSP_FILTER_REF:
367 result = g_list_prepend (result, g_object_ref (media));
369 case GST_RTSP_FILTER_KEEP:
374 g_mutex_unlock (&priv->lock);
380 * gst_rtsp_session_new:
381 * @sessionid: a session id
383 * Create a new #GstRTSPSession instance with @sessionid.
386 gst_rtsp_session_new (const gchar * sessionid)
388 GstRTSPSession *result;
390 g_return_val_if_fail (sessionid != NULL, NULL);
392 result = g_object_new (GST_TYPE_RTSP_SESSION, "sessionid", sessionid, NULL);
398 * gst_rtsp_session_get_sessionid:
399 * @session: a #GstRTSPSession
401 * Get the sessionid of @session.
403 * Returns: the sessionid of @session. The value remains valid as long as
407 gst_rtsp_session_get_sessionid (GstRTSPSession * session)
409 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL);
411 return session->priv->sessionid;
415 * gst_rtsp_session_get_header:
416 * @session: a #GstRTSPSession
418 * Get the string that can be placed in the Session header field.
420 * Returns: (transfer full): the Session header of @session. g_free() after usage.
423 gst_rtsp_session_get_header (GstRTSPSession * session)
425 GstRTSPSessionPrivate *priv;
428 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL);
430 priv = session->priv;
432 g_mutex_lock (&priv->lock);
433 if (priv->timeout != 60)
434 result = g_strdup_printf ("%s; timeout=%d", priv->sessionid, priv->timeout);
436 result = g_strdup (priv->sessionid);
437 g_mutex_unlock (&priv->lock);
443 * gst_rtsp_session_set_timeout:
444 * @session: a #GstRTSPSession
445 * @timeout: the new timeout
447 * Configure @session for a timeout of @timeout seconds. The session will be
448 * cleaned up when there is no activity for @timeout seconds.
451 gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout)
453 GstRTSPSessionPrivate *priv;
455 g_return_if_fail (GST_IS_RTSP_SESSION (session));
457 priv = session->priv;
459 g_mutex_lock (&priv->lock);
460 priv->timeout = timeout;
461 g_mutex_unlock (&priv->lock);
465 * gst_rtsp_session_get_timeout:
466 * @session: a #GstRTSPSession
468 * Get the timeout value of @session.
470 * Returns: the timeout of @session in seconds.
473 gst_rtsp_session_get_timeout (GstRTSPSession * session)
475 GstRTSPSessionPrivate *priv;
478 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0);
480 priv = session->priv;
482 g_mutex_lock (&priv->lock);
484 g_mutex_unlock (&priv->lock);
490 * gst_rtsp_session_touch:
491 * @session: a #GstRTSPSession
493 * Update the last_access time of the session to the current time.
496 gst_rtsp_session_touch (GstRTSPSession * session)
498 GstRTSPSessionPrivate *priv;
500 g_return_if_fail (GST_IS_RTSP_SESSION (session));
502 priv = session->priv;
504 g_mutex_lock (&priv->lock);
505 g_get_current_time (&priv->last_access);
506 g_mutex_unlock (&priv->lock);
510 * gst_rtsp_session_prevent_expire:
511 * @session: a #GstRTSPSession
513 * Prevent @session from expiring.
516 gst_rtsp_session_prevent_expire (GstRTSPSession * session)
518 g_return_if_fail (GST_IS_RTSP_SESSION (session));
520 g_atomic_int_add (&session->priv->expire_count, 1);
524 * gst_rtsp_session_allow_expire:
525 * @session: a #GstRTSPSession
527 * Allow @session to expire. This method must be called an equal
528 * amount of time as gst_rtsp_session_prevent_expire().
531 gst_rtsp_session_allow_expire (GstRTSPSession * session)
533 g_atomic_int_add (&session->priv->expire_count, -1);
537 * gst_rtsp_session_next_timeout:
538 * @session: a #GstRTSPSession
539 * @now: the current system time
541 * Get the amount of milliseconds till the session will expire.
543 * Returns: the amount of milliseconds since the session will time out.
546 gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now)
548 GstRTSPSessionPrivate *priv;
550 GstClockTime last_access, now_ns;
552 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1);
553 g_return_val_if_fail (now != NULL, -1);
555 priv = session->priv;
557 g_mutex_lock (&priv->lock);
558 if (g_atomic_int_get (&priv->expire_count) != 0) {
559 /* touch session when the expire count is not 0 */
560 g_get_current_time (&priv->last_access);
563 last_access = GST_TIMEVAL_TO_TIME (priv->last_access);
564 /* add timeout allow for 5 seconds of extra time */
565 last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND);
566 g_mutex_unlock (&priv->lock);
568 now_ns = GST_TIMEVAL_TO_TIME (*now);
570 if (last_access > now_ns)
571 res = GST_TIME_AS_MSECONDS (last_access - now_ns);
579 * gst_rtsp_session_is_expired:
580 * @session: a #GstRTSPSession
581 * @now: the current system time
583 * Check if @session timeout out.
585 * Returns: %TRUE if @session timed out
588 gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now)
592 res = (gst_rtsp_session_next_timeout (session, now) == 0);