docs: update docs
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-mount-points.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #include <string.h>
21
22 #include "rtsp-mount-points.h"
23
24 #define GST_RTSP_MOUNT_POINTS_GET_PRIVATE(obj)  \
25        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MOUNT_POINTS, GstRTSPMountPointsPrivate))
26
27 typedef struct
28 {
29   gchar *path;
30   gint len;
31   GstRTSPMediaFactory *factory;
32 } DataItem;
33
34 static DataItem *
35 data_item_new (gchar * path, gint len, GstRTSPMediaFactory * factory)
36 {
37   DataItem *item;
38
39   item = g_slice_alloc (sizeof (DataItem));
40   item->path = path;
41   item->len = len;
42   item->factory = factory;
43
44   return item;
45 }
46
47 static void
48 data_item_free (gpointer data)
49 {
50   DataItem *item = data;
51
52   g_free (item->path);
53   g_object_unref (item->factory);
54   g_slice_free1 (sizeof (DataItem), item);
55 }
56
57 static void
58 data_item_dump (gconstpointer a, gpointer prefix)
59 {
60   const DataItem *item = a;
61
62   GST_DEBUG ("%s%s %p\n", (gchar *) prefix, item->path, item->factory);
63 }
64
65 static gint
66 data_item_compare (gconstpointer a, gconstpointer b, gpointer user_data)
67 {
68   const DataItem *item1 = a, *item2 = b;
69   gint res;
70
71   res = g_strcmp0 (item1->path, item2->path);
72
73   return res;
74 }
75
76 struct _GstRTSPMountPointsPrivate
77 {
78   GMutex lock;
79   GSequence *mounts;            /* protected by lock */
80   gboolean dirty;
81 };
82
83 G_DEFINE_TYPE (GstRTSPMountPoints, gst_rtsp_mount_points, G_TYPE_OBJECT);
84
85 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
86 #define GST_CAT_DEFAULT rtsp_media_debug
87
88 static void gst_rtsp_mount_points_finalize (GObject * obj);
89
90 static void
91 gst_rtsp_mount_points_class_init (GstRTSPMountPointsClass * klass)
92 {
93   GObjectClass *gobject_class;
94
95   g_type_class_add_private (klass, sizeof (GstRTSPMountPointsPrivate));
96
97   gobject_class = G_OBJECT_CLASS (klass);
98
99   gobject_class->finalize = gst_rtsp_mount_points_finalize;
100
101   GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmountpoints", 0,
102       "GstRTSPMountPoints");
103 }
104
105 static void
106 gst_rtsp_mount_points_init (GstRTSPMountPoints * mounts)
107 {
108   GstRTSPMountPointsPrivate *priv = GST_RTSP_MOUNT_POINTS_GET_PRIVATE (mounts);
109
110   GST_DEBUG_OBJECT (mounts, "created");
111
112   mounts->priv = priv;
113
114   g_mutex_init (&priv->lock);
115   priv->mounts = g_sequence_new (data_item_free);
116   priv->dirty = FALSE;
117 }
118
119 static void
120 gst_rtsp_mount_points_finalize (GObject * obj)
121 {
122   GstRTSPMountPoints *mounts = GST_RTSP_MOUNT_POINTS (obj);
123   GstRTSPMountPointsPrivate *priv = mounts->priv;
124
125   GST_DEBUG_OBJECT (mounts, "finalized");
126
127   g_sequence_free (priv->mounts);
128   g_mutex_clear (&priv->lock);
129
130   G_OBJECT_CLASS (gst_rtsp_mount_points_parent_class)->finalize (obj);
131 }
132
133 /**
134  * gst_rtsp_mount_points_new:
135  *
136  * Make a new mount points object.
137  *
138  * Returns: a new #GstRTSPMountPoints
139  */
140 GstRTSPMountPoints *
141 gst_rtsp_mount_points_new (void)
142 {
143   GstRTSPMountPoints *result;
144
145   result = g_object_new (GST_TYPE_RTSP_MOUNT_POINTS, NULL);
146
147   return result;
148 }
149
150 static gboolean
151 has_prefix (DataItem * str, DataItem * prefix)
152 {
153   /* prefix needs to be smaller than str */
154   if (str->len < prefix->len)
155     return FALSE;
156
157   /* if str is larger, it there should be a / following the prefix */
158   if (str->len > prefix->len && str->path[prefix->len] != '/')
159     return FALSE;
160
161   return strncmp (str->path, prefix->path, prefix->len) == 0;
162 }
163
164 /**
165  * gst_rtsp_mount_points_match:
166  * @mounts: a #GstRTSPMountPoints
167  * @path: a mount point
168  * @matched: the amount of @path matched
169  *
170  * Find the factory in @mounts that has the longest match with @path.
171  *
172  * If @matched is NULL, @path willt match the factory exactly otherwise
173  * the amount of characters that matched is returned in @matched.
174  *
175  * Returns: (transfer full): the #GstRTSPMediaFactory for @path.
176  *          g_object_unref() after usage.
177  */
178 GstRTSPMediaFactory *
179 gst_rtsp_mount_points_match (GstRTSPMountPoints * mounts,
180     const gchar * path, gint * matched)
181 {
182   GstRTSPMountPointsPrivate *priv;
183   GstRTSPMediaFactory *result = NULL;
184   GSequenceIter *iter, *best;
185   DataItem item, *ritem;
186
187   g_return_val_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts), NULL);
188   g_return_val_if_fail (path != NULL, NULL);
189
190   priv = mounts->priv;
191
192   item.path = (gchar *) path;
193   item.len = strlen (path);
194
195   g_mutex_lock (&priv->lock);
196   if (priv->dirty) {
197     g_sequence_sort (priv->mounts, data_item_compare, mounts);
198     g_sequence_foreach (priv->mounts, (GFunc) data_item_dump, "sort :");
199     priv->dirty = FALSE;
200   }
201
202   /* find the location of the media in the hashtable we only use the absolute
203    * path of the uri to find a media factory. If the factory depends on other
204    * properties found in the url, this method should be overridden. */
205   iter = g_sequence_get_begin_iter (priv->mounts);
206   best = NULL;
207   while (!g_sequence_iter_is_end (iter)) {
208     ritem = g_sequence_get (iter);
209
210     data_item_dump (ritem, "inspect: ");
211
212     if (best == NULL) {
213       if (has_prefix (&item, ritem)) {
214         data_item_dump (ritem, "prefix: ");
215         best = iter;
216       }
217     } else {
218       if (!has_prefix (&item, ritem))
219         break;
220
221       best = iter;
222       data_item_dump (ritem, "new best: ");
223     }
224     iter = g_sequence_iter_next (iter);
225   }
226   if (best) {
227     ritem = g_sequence_get (best);
228     data_item_dump (ritem, "result: ");
229     if (matched || ritem->len == item.len) {
230       result = g_object_ref (ritem->factory);
231       if (matched)
232         *matched = ritem->len;
233     }
234   }
235   g_mutex_unlock (&priv->lock);
236
237   GST_INFO ("found media factory %p for path %s", result, path);
238
239   return result;
240 }
241
242 /**
243  * gst_rtsp_mount_points_add_factory:
244  * @mounts: a #GstRTSPMountPoints
245  * @path: a mount point
246  * @factory: (transfer full): a #GstRTSPMediaFactory
247  *
248  * Attach @factory to the mount point @path in @mounts.
249  *
250  * @path is of the form (/node)+. Any previous mount point will be freed.
251  *
252  * Ownership is taken of the reference on @factory so that @factory should not be
253  * used after calling this function.
254  */
255 void
256 gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts,
257     const gchar * path, GstRTSPMediaFactory * factory)
258 {
259   GstRTSPMountPointsPrivate *priv;
260   DataItem *item;
261
262   g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts));
263   g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
264   g_return_if_fail (path != NULL);
265
266   priv = mounts->priv;
267
268   item = data_item_new (g_strdup (path), strlen (path), factory);
269
270   g_mutex_lock (&priv->lock);
271   g_sequence_append (priv->mounts, item);
272   priv->dirty = TRUE;
273   g_mutex_unlock (&priv->lock);
274 }
275
276 /**
277  * gst_rtsp_mount_points_remove_factory:
278  * @mounts: a #GstRTSPMountPoints
279  * @path: a mount point
280  *
281  * Remove the #GstRTSPMediaFactory associated with @path in @mounts.
282  */
283 void
284 gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts,
285     const gchar * path)
286 {
287   GstRTSPMountPointsPrivate *priv;
288   DataItem item;
289   GSequenceIter *iter;
290
291   g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts));
292   g_return_if_fail (path != NULL);
293
294   priv = mounts->priv;
295
296   item.path = (gchar *) path;
297
298   g_mutex_lock (&priv->lock);
299   iter = g_sequence_lookup (priv->mounts, &item, data_item_compare, mounts);
300   if (iter) {
301     g_sequence_remove (iter);
302     priv->dirty = TRUE;
303   }
304   g_mutex_unlock (&priv->lock);
305 }