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.
21 #include "rtsp-session.h"
23 #define GST_RTSP_SESSION_GET_PRIVATE(obj) \
24 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION, GstRTSPSessionPrivate))
26 struct _GstRTSPSessionPrivate
28 GMutex lock; /* protects everything but sessionid and create_time */
32 GTimeVal create_time; /* immutable */
41 #define DEFAULT_TIMEOUT 60
51 GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
52 #define GST_CAT_DEFAULT rtsp_session_debug
54 static void gst_rtsp_session_get_property (GObject * object, guint propid,
55 GValue * value, GParamSpec * pspec);
56 static void gst_rtsp_session_set_property (GObject * object, guint propid,
57 const GValue * value, GParamSpec * pspec);
58 static void gst_rtsp_session_finalize (GObject * obj);
60 G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT);
63 gst_rtsp_session_class_init (GstRTSPSessionClass * klass)
65 GObjectClass *gobject_class;
67 g_type_class_add_private (klass, sizeof (GstRTSPSessionPrivate));
69 gobject_class = G_OBJECT_CLASS (klass);
71 gobject_class->get_property = gst_rtsp_session_get_property;
72 gobject_class->set_property = gst_rtsp_session_set_property;
73 gobject_class->finalize = gst_rtsp_session_finalize;
75 g_object_class_install_property (gobject_class, PROP_SESSIONID,
76 g_param_spec_string ("sessionid", "Sessionid", "the session id",
77 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
78 G_PARAM_STATIC_STRINGS));
80 g_object_class_install_property (gobject_class, PROP_TIMEOUT,
81 g_param_spec_uint ("timeout", "timeout",
82 "the timeout of the session (0 = never)", 0, G_MAXUINT,
83 DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
85 GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
90 gst_rtsp_session_init (GstRTSPSession * session)
92 GstRTSPSessionPrivate *priv = GST_RTSP_SESSION_GET_PRIVATE (session);
96 g_mutex_init (&priv->lock);
97 priv->timeout = DEFAULT_TIMEOUT;
98 g_get_current_time (&priv->create_time);
99 gst_rtsp_session_touch (session);
103 gst_rtsp_session_finalize (GObject * obj)
105 GstRTSPSession *session;
106 GstRTSPSessionPrivate *priv;
108 session = GST_RTSP_SESSION (obj);
109 priv = session->priv;
111 GST_INFO ("finalize session %p", session);
114 g_list_free_full (priv->medias, g_object_unref);
116 /* free session id */
117 g_free (priv->sessionid);
118 g_mutex_clear (&priv->lock);
120 G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj);
124 gst_rtsp_session_get_property (GObject * object, guint propid,
125 GValue * value, GParamSpec * pspec)
127 GstRTSPSession *session = GST_RTSP_SESSION (object);
128 GstRTSPSessionPrivate *priv = session->priv;
132 g_value_set_string (value, priv->sessionid);
135 g_value_set_uint (value, gst_rtsp_session_get_timeout (session));
138 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
143 gst_rtsp_session_set_property (GObject * object, guint propid,
144 const GValue * value, GParamSpec * pspec)
146 GstRTSPSession *session = GST_RTSP_SESSION (object);
147 GstRTSPSessionPrivate *priv = session->priv;
151 g_free (priv->sessionid);
152 priv->sessionid = g_value_dup_string (value);
155 gst_rtsp_session_set_timeout (session, g_value_get_uint (value));
158 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
163 * gst_rtsp_session_manage_media:
164 * @sess: a #GstRTSPSession
165 * @path: the path for the media
166 * @media: (transfer full): a #GstRTSPMedia
168 * Manage the media object @obj in @sess. @path will be used to retrieve this
169 * media from the session with gst_rtsp_session_get_media().
171 * Ownership is taken from @media.
173 * Returns: (transfer none): a new @GstRTSPSessionMedia object.
175 GstRTSPSessionMedia *
176 gst_rtsp_session_manage_media (GstRTSPSession * sess, const gchar * path,
177 GstRTSPMedia * media)
179 GstRTSPSessionPrivate *priv;
180 GstRTSPSessionMedia *result;
182 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
183 g_return_val_if_fail (path != NULL, NULL);
184 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
185 g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
186 GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
190 result = gst_rtsp_session_media_new (path, media);
192 g_mutex_lock (&priv->lock);
193 priv->medias = g_list_prepend (priv->medias, result);
194 g_mutex_unlock (&priv->lock);
196 GST_INFO ("manage new media %p in session %p", media, result);
202 * gst_rtsp_session_release_media:
203 * @sess: a #GstRTSPSession
204 * @media: a #GstRTSPMedia
206 * Release the managed @media in @sess, freeing the memory allocated by it.
208 * Returns: %TRUE if there are more media session left in @sess.
211 gst_rtsp_session_release_media (GstRTSPSession * sess,
212 GstRTSPSessionMedia * media)
214 GstRTSPSessionPrivate *priv;
218 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE);
219 g_return_val_if_fail (media != NULL, FALSE);
223 g_mutex_lock (&priv->lock);
224 find = g_list_find (priv->medias, media);
226 priv->medias = g_list_delete_link (priv->medias, find);
227 more = (priv->medias != NULL);
228 g_mutex_unlock (&priv->lock);
231 g_object_unref (media);
237 * gst_rtsp_session_get_media:
238 * @sess: a #GstRTSPSession
239 * @path: the path for the media
240 * @matched: the amount of matched characters
242 * Get the session media for @path. @matched will contain the number of matched
243 * characters of @path.
245 * Returns: (transfer none): the configuration for @path in @sess.
247 GstRTSPSessionMedia *
248 gst_rtsp_session_get_media (GstRTSPSession * sess, const gchar * path,
251 GstRTSPSessionPrivate *priv;
252 GstRTSPSessionMedia *result;
256 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
257 g_return_val_if_fail (path != NULL, NULL);
263 g_mutex_lock (&priv->lock);
264 for (walk = priv->medias; walk; walk = g_list_next (walk)) {
265 GstRTSPSessionMedia *test;
267 test = (GstRTSPSessionMedia *) walk->data;
269 /* find largest match */
270 if (gst_rtsp_session_media_matches (test, path, matched)) {
271 if (best < *matched) {
277 g_mutex_unlock (&priv->lock);
285 * gst_rtsp_session_filter:
286 * @sess: a #GstRTSPSession
287 * @func: (scope call): a callback
288 * @user_data: user data passed to @func
290 * Call @func for each media in @sess. The result value of @func determines
291 * what happens to the media. @func will be called with @sess
292 * locked so no further actions on @sess can be performed from @func.
294 * If @func returns #GST_RTSP_FILTER_REMOVE, the media will be removed from
297 * If @func returns #GST_RTSP_FILTER_KEEP, the media will remain in @sess.
299 * If @func returns #GST_RTSP_FILTER_REF, the media will remain in @sess but
300 * will also be added with an additional ref to the result #GList of this
303 * Returns: (element-type GstRTSPSessionMedia) (transfer full): a GList with all
304 * media for which @func returned #GST_RTSP_FILTER_REF. After usage, each
305 * element in the #GList should be unreffed before the list is freed.
308 gst_rtsp_session_filter (GstRTSPSession * sess,
309 GstRTSPSessionFilterFunc func, gpointer user_data)
311 GstRTSPSessionPrivate *priv;
312 GList *result, *walk, *next;
314 g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
315 g_return_val_if_fail (func != NULL, NULL);
321 g_mutex_lock (&priv->lock);
322 for (walk = priv->medias; walk; walk = next) {
323 GstRTSPSessionMedia *media = walk->data;
325 next = g_list_next (walk);
327 switch (func (sess, media, user_data)) {
328 case GST_RTSP_FILTER_REMOVE:
329 g_object_unref (media);
330 priv->medias = g_list_delete_link (priv->medias, walk);
332 case GST_RTSP_FILTER_REF:
333 result = g_list_prepend (result, g_object_ref (media));
335 case GST_RTSP_FILTER_KEEP:
340 g_mutex_unlock (&priv->lock);
346 * gst_rtsp_session_new:
347 * @sessionid: a session id
349 * Create a new #GstRTSPSession instance with @sessionid.
352 gst_rtsp_session_new (const gchar * sessionid)
354 GstRTSPSession *result;
356 g_return_val_if_fail (sessionid != NULL, NULL);
358 result = g_object_new (GST_TYPE_RTSP_SESSION, "sessionid", sessionid, NULL);
364 * gst_rtsp_session_get_sessionid:
365 * @session: a #GstRTSPSession
367 * Get the sessionid of @session.
369 * Returns: the sessionid of @session. The value remains valid as long as
373 gst_rtsp_session_get_sessionid (GstRTSPSession * session)
375 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL);
377 return session->priv->sessionid;
381 * gst_rtsp_session_get_header:
382 * @session: a #GstRTSPSession
384 * Get the string that can be placed in the Session header field.
386 * Returns: (transfer full): the Session header of @session. g_free() after usage.
389 gst_rtsp_session_get_header (GstRTSPSession * session)
391 GstRTSPSessionPrivate *priv;
394 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), NULL);
396 priv = session->priv;
398 g_mutex_lock (&priv->lock);
399 if (priv->timeout != 60)
400 result = g_strdup_printf ("%s; timeout=%d", priv->sessionid, priv->timeout);
402 result = g_strdup (priv->sessionid);
403 g_mutex_unlock (&priv->lock);
409 * gst_rtsp_session_set_timeout:
410 * @session: a #GstRTSPSession
411 * @timeout: the new timeout
413 * Configure @session for a timeout of @timeout seconds. The session will be
414 * cleaned up when there is no activity for @timeout seconds.
417 gst_rtsp_session_set_timeout (GstRTSPSession * session, guint timeout)
419 GstRTSPSessionPrivate *priv;
421 g_return_if_fail (GST_IS_RTSP_SESSION (session));
423 priv = session->priv;
425 g_mutex_lock (&priv->lock);
426 priv->timeout = timeout;
427 g_mutex_unlock (&priv->lock);
431 * gst_rtsp_session_get_timeout:
432 * @session: a #GstRTSPSession
434 * Get the timeout value of @session.
436 * Returns: the timeout of @session in seconds.
439 gst_rtsp_session_get_timeout (GstRTSPSession * session)
441 GstRTSPSessionPrivate *priv;
444 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), 0);
446 priv = session->priv;
448 g_mutex_lock (&priv->lock);
450 g_mutex_unlock (&priv->lock);
456 * gst_rtsp_session_touch:
457 * @session: a #GstRTSPSession
459 * Update the last_access time of the session to the current time.
462 gst_rtsp_session_touch (GstRTSPSession * session)
464 GstRTSPSessionPrivate *priv;
466 g_return_if_fail (GST_IS_RTSP_SESSION (session));
468 priv = session->priv;
470 g_mutex_lock (&priv->lock);
471 g_get_current_time (&priv->last_access);
472 g_mutex_unlock (&priv->lock);
476 * gst_rtsp_session_prevent_expire:
477 * @session: a #GstRTSPSession
479 * Prevent @session from expiring.
482 gst_rtsp_session_prevent_expire (GstRTSPSession * session)
484 g_return_if_fail (GST_IS_RTSP_SESSION (session));
486 g_atomic_int_add (&session->priv->expire_count, 1);
490 * gst_rtsp_session_allow_expire:
491 * @session: a #GstRTSPSession
493 * Allow @session to expire. This method must be called an equal
494 * amount of time as gst_rtsp_session_prevent_expire().
497 gst_rtsp_session_allow_expire (GstRTSPSession * session)
499 g_atomic_int_add (&session->priv->expire_count, -1);
503 * gst_rtsp_session_next_timeout:
504 * @session: a #GstRTSPSession
505 * @now: the current system time
507 * Get the amount of milliseconds till the session will expire.
509 * Returns: the amount of milliseconds since the session will time out.
512 gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now)
514 GstRTSPSessionPrivate *priv;
516 GstClockTime last_access, now_ns;
518 g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1);
519 g_return_val_if_fail (now != NULL, -1);
521 priv = session->priv;
523 g_mutex_lock (&priv->lock);
524 if (g_atomic_int_get (&priv->expire_count) != 0) {
525 /* touch session when the expire count is not 0 */
526 g_get_current_time (&priv->last_access);
529 last_access = GST_TIMEVAL_TO_TIME (priv->last_access);
530 /* add timeout allow for 5 seconds of extra time */
531 last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND);
532 g_mutex_unlock (&priv->lock);
534 now_ns = GST_TIMEVAL_TO_TIME (*now);
536 if (last_access > now_ns)
537 res = GST_TIME_AS_MSECONDS (last_access - now_ns);
545 * gst_rtsp_session_is_expired:
546 * @session: a #GstRTSPSession
547 * @now: the current system time
549 * Check if @session timeout out.
551 * Returns: %TRUE if @session timed out
554 gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now)
558 res = (gst_rtsp_session_next_timeout (session, now) == 0);