Document locking and its order
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-session-media.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 #include <string.h>
20
21 #include "rtsp-session.h"
22
23 #define GST_RTSP_SESSION_MEDIA_GET_PRIVATE(obj)  \
24     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaPrivate))
25
26 struct _GstRTSPSessionMediaPrivate
27 {
28   GMutex lock;
29   GstRTSPUrl *url;              /* unmutable */
30   GstRTSPMedia *media;          /* unmutable */
31   GstRTSPState state;           /* protected by lock */
32   guint counter;                /* protected by lock */
33
34   GPtrArray *transports;        /* protected by lock */
35 };
36
37 enum
38 {
39   PROP_0,
40   PROP_LAST
41 };
42
43 GST_DEBUG_CATEGORY_STATIC (rtsp_session_media_debug);
44 #define GST_CAT_DEFAULT rtsp_session_media_debug
45
46 static void gst_rtsp_session_media_finalize (GObject * obj);
47
48 G_DEFINE_TYPE (GstRTSPSessionMedia, gst_rtsp_session_media, G_TYPE_OBJECT);
49
50 static void
51 gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass)
52 {
53   GObjectClass *gobject_class;
54
55   g_type_class_add_private (klass, sizeof (GstRTSPSessionMediaPrivate));
56
57   gobject_class = G_OBJECT_CLASS (klass);
58
59   gobject_class->finalize = gst_rtsp_session_media_finalize;
60
61   GST_DEBUG_CATEGORY_INIT (rtsp_session_media_debug, "rtspsessionmedia", 0,
62       "GstRTSPSessionMedia");
63 }
64
65 static void
66 gst_rtsp_session_media_init (GstRTSPSessionMedia * media)
67 {
68   GstRTSPSessionMediaPrivate *priv = GST_RTSP_SESSION_MEDIA_GET_PRIVATE (media);
69
70   media->priv = priv;
71
72   g_mutex_init (&priv->lock);
73   priv->state = GST_RTSP_STATE_INIT;
74 }
75
76 static void
77 gst_rtsp_session_media_finalize (GObject * obj)
78 {
79   GstRTSPSessionMedia *media;
80   GstRTSPSessionMediaPrivate *priv;
81
82   media = GST_RTSP_SESSION_MEDIA (obj);
83   priv = media->priv;
84
85   GST_INFO ("free session media %p", media);
86
87   gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
88
89   g_ptr_array_unref (priv->transports);
90
91   gst_rtsp_url_free (priv->url);
92   g_object_unref (priv->media);
93   g_mutex_clear (&priv->lock);
94
95   G_OBJECT_CLASS (gst_rtsp_session_media_parent_class)->finalize (obj);
96 }
97
98 static void
99 free_session_media (gpointer data)
100 {
101   if (data)
102     g_object_unref (data);
103 }
104
105 /**
106  * gst_rtsp_session_media_new:
107  * @url: the #GstRTSPUrl
108  * @media: the #GstRTSPMedia
109  *
110  * Create a new #GstRTPSessionMedia that manages the streams
111  * in @media for @url. @media should be prepared.
112  *
113  * Ownership is taken of @media.
114  *
115  * Returns: a new #GstRTSPSessionMedia.
116  */
117 GstRTSPSessionMedia *
118 gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
119 {
120   GstRTSPSessionMediaPrivate *priv;
121   GstRTSPSessionMedia *result;
122   guint n_streams;
123
124   g_return_val_if_fail (url != NULL, NULL);
125   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
126   g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
127       GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
128
129   result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL);
130   priv = result->priv;
131
132   priv->url = gst_rtsp_url_copy ((GstRTSPUrl *) url);
133   priv->media = media;
134
135   /* prealloc the streams now, filled with NULL */
136   n_streams = gst_rtsp_media_n_streams (media);
137   priv->transports = g_ptr_array_new_full (n_streams, free_session_media);
138   g_ptr_array_set_size (priv->transports, n_streams);
139
140   return result;
141 }
142
143 /**
144  * gst_rtsp_session_media_matches_url:
145  * @media: a #GstRTSPSessionMedia
146  * @url: a #GstRTSPUrl
147  *
148  * Check if the url of @media matches @url.
149  *
150  * Returns: %TRUE when @url matches the url of @media.
151  */
152 gboolean
153 gst_rtsp_session_media_matches_url (GstRTSPSessionMedia * media,
154     const GstRTSPUrl * url)
155 {
156   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
157   g_return_val_if_fail (url != NULL, FALSE);
158
159   return g_str_equal (media->priv->url->abspath, url->abspath);
160 }
161
162 /**
163  * gst_rtsp_session_media_get_media:
164  * @media: a #GstRTSPSessionMedia
165  *
166  * Get the #GstRTSPMedia that was used when constructing @media
167  *
168  * Returns: (transfer none): the #GstRTSPMedia of @media. Remains valid as long
169  *         as @media is valid.
170  */
171 GstRTSPMedia *
172 gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media)
173 {
174   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
175
176   return media->priv->media;
177 }
178
179 /**
180  * gst_rtsp_session_media_set_transport:
181  * @media: a #GstRTSPSessionMedia
182  * @stream: a #GstRTSPStream
183  * @tr: a #GstRTSPTransport
184  *
185  * Configure the transport for @stream to @tr in @media.
186  *
187  * Returns: (transfer none): the new or updated #GstRTSPStreamTransport for @stream.
188  */
189 GstRTSPStreamTransport *
190 gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
191     GstRTSPStream * stream, GstRTSPTransport * tr)
192 {
193   GstRTSPSessionMediaPrivate *priv;
194   GstRTSPStreamTransport *result;
195   guint idx;
196
197   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
198   g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
199   g_return_val_if_fail (tr != NULL, NULL);
200   priv = media->priv;
201   idx = gst_rtsp_stream_get_index (stream);
202   g_return_val_if_fail (idx < priv->transports->len, NULL);
203
204   g_mutex_lock (&priv->lock);
205   result = g_ptr_array_index (priv->transports, idx);
206   if (result == NULL) {
207     result = gst_rtsp_stream_transport_new (stream, tr);
208     g_ptr_array_index (priv->transports, idx) = result;
209     g_mutex_unlock (&priv->lock);
210   } else {
211     gst_rtsp_stream_transport_set_transport (result, tr);
212     g_mutex_unlock (&priv->lock);
213   }
214
215   return result;
216 }
217
218 /**
219  * gst_rtsp_session_media_get_transport:
220  * @media: a #GstRTSPSessionMedia
221  * @idx: the stream index
222  *
223  * Get a previously created #GstRTSPStreamTransport for the stream at @idx.
224  *
225  * Returns: (transfer none): a #GstRTSPStreamTransport that is valid until the
226  * session of @media is unreffed.
227  */
228 GstRTSPStreamTransport *
229 gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx)
230 {
231   GstRTSPSessionMediaPrivate *priv;
232   GstRTSPStreamTransport *result;
233
234   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
235   priv = media->priv;
236   g_return_val_if_fail (idx < priv->transports->len, NULL);
237
238   g_mutex_lock (&priv->lock);
239   result = g_ptr_array_index (priv->transports, idx);
240   g_mutex_unlock (&priv->lock);
241
242   return result;
243 }
244
245 /**
246  * gst_rtsp_session_media_alloc_channels:
247  * @media: a #GstRTSPSessionMedia
248  * @range: a #GstRTSPRange
249  *
250  * Fill @range with the next available min and max channels for
251  * interleaved transport.
252  *
253  * Returns: %TRUE on success.
254  */
255 gboolean
256 gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media,
257     GstRTSPRange * range)
258 {
259   GstRTSPSessionMediaPrivate *priv;
260
261   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
262
263   priv = media->priv;
264
265   g_mutex_lock (&priv->lock);
266   range->min = priv->counter++;
267   range->max = priv->counter++;
268   g_mutex_unlock (&priv->lock);
269
270   return TRUE;
271 }
272
273 /**
274  * gst_rtsp_session_media_set_state:
275  * @media: a #GstRTSPSessionMedia
276  * @state: the new state
277  *
278  * Tell the media object @media to change to @state.
279  *
280  * Returns: %TRUE on success.
281  */
282 gboolean
283 gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state)
284 {
285   GstRTSPSessionMediaPrivate *priv;
286   gboolean ret;
287
288   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
289
290   priv = media->priv;
291
292   g_mutex_lock (&priv->lock);
293   ret = gst_rtsp_media_set_state (priv->media, state, priv->transports);
294   g_mutex_unlock (&priv->lock);
295
296   return ret;
297 }
298
299 /**
300  * gst_rtsp_session_media_set_rtsp_state:
301  * @media: a #GstRTSPSessionMedia
302  * @state: a #GstRTSPState
303  *
304  * Set the RTSP state of @media to @state.
305  */
306 void
307 gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia * media,
308     GstRTSPState state)
309 {
310   GstRTSPSessionMediaPrivate *priv;
311
312   g_return_if_fail (GST_IS_RTSP_SESSION_MEDIA (media));
313
314   priv = media->priv;
315
316   g_mutex_lock (&priv->lock);
317   priv->state = state;
318   g_mutex_unlock (&priv->lock);
319 }
320
321 /**
322  * gst_rtsp_session_media_set_rtsp_state:
323  * @media: a #GstRTSPSessionMedia
324  *
325  * Get the current RTSP state of @media.
326  *
327  * Returns: the current RTSP state of @media.
328  */
329 GstRTSPState
330 gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia * media)
331 {
332   GstRTSPSessionMediaPrivate *priv;
333   GstRTSPState ret;
334
335   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media),
336       GST_RTSP_STATE_INVALID);
337
338   priv = media->priv;
339
340   g_mutex_lock (&priv->lock);
341   ret = priv->state;
342   g_mutex_unlock (&priv->lock);
343
344   return ret;
345 }