session-media: calculate start-time
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-stream-transport.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  * SECTION:rtsp-stream-transport
21  * @short_description: A media stream transport configuration
22  * @see_also: #GstRTSPStream, #GstRTSPSessionMedia
23  *
24  * The #GstRTSPStreamTransport configures the transport used by a
25  * #GstRTSPStream. It is usually manages by a #GstRTSPSessionMedia object.
26  *
27  * With gst_rtsp_stream_transport_set_callbacks(), callbacks can be configured
28  * to handle the RTP and RTCP packets from the stream, for example when they
29  * need to be sent over TCP.
30  *
31  * With  gst_rtsp_stream_transport_set_active() the transports are added and
32  * removed from the stream.
33  *
34  * A #GstRTSPStream will call gst_rtsp_stream_transport_keep_alive() when RTCP
35  * is received from the client. It will also call
36  * gst_rtsp_stream_transport_set_timed_out() when a receiver has timed out.
37  *
38  * Last reviewed on 2013-07-16 (1.0.0)
39  */
40
41 #include <string.h>
42 #include <stdlib.h>
43
44 #include "rtsp-stream-transport.h"
45
46 #define GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE(obj)  \
47        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportPrivate))
48
49 struct _GstRTSPStreamTransportPrivate
50 {
51   GstRTSPStream *stream;
52
53   GstRTSPSendFunc send_rtp;
54   GstRTSPSendFunc send_rtcp;
55   gpointer user_data;
56   GDestroyNotify notify;
57
58   GstRTSPKeepAliveFunc keep_alive;
59   gpointer ka_user_data;
60   GDestroyNotify ka_notify;
61   gboolean active;
62   gboolean timed_out;
63
64   GstRTSPTransport *transport;
65   GstRTSPUrl *url;
66
67   GObject *rtpsource;
68 };
69
70 enum
71 {
72   PROP_0,
73   PROP_LAST
74 };
75
76 GST_DEBUG_CATEGORY_STATIC (rtsp_stream_transport_debug);
77 #define GST_CAT_DEFAULT rtsp_stream_transport_debug
78
79 static void gst_rtsp_stream_transport_finalize (GObject * obj);
80
81 G_DEFINE_TYPE (GstRTSPStreamTransport, gst_rtsp_stream_transport,
82     G_TYPE_OBJECT);
83
84 static void
85 gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass)
86 {
87   GObjectClass *gobject_class;
88
89   g_type_class_add_private (klass, sizeof (GstRTSPStreamTransportPrivate));
90
91   gobject_class = G_OBJECT_CLASS (klass);
92
93   gobject_class->finalize = gst_rtsp_stream_transport_finalize;
94
95   GST_DEBUG_CATEGORY_INIT (rtsp_stream_transport_debug, "rtspmediatransport",
96       0, "GstRTSPStreamTransport");
97 }
98
99 static void
100 gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans)
101 {
102   GstRTSPStreamTransportPrivate *priv =
103       GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE (trans);
104
105   trans->priv = priv;
106 }
107
108 static void
109 gst_rtsp_stream_transport_finalize (GObject * obj)
110 {
111   GstRTSPStreamTransportPrivate *priv;
112   GstRTSPStreamTransport *trans;
113
114   trans = GST_RTSP_STREAM_TRANSPORT (obj);
115   priv = trans->priv;
116
117   /* remove callbacks now */
118   gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL);
119   gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL);
120
121   if (priv->transport)
122     gst_rtsp_transport_free (priv->transport);
123
124   if (priv->url)
125     gst_rtsp_url_free (priv->url);
126
127   G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj);
128 }
129
130 /**
131  * gst_rtsp_stream_transport_new:
132  * @stream: a #GstRTSPStream
133  * @tr: (transfer full): a GstRTSPTransport
134  *
135  * Create a new #GstRTSPStreamTransport that can be used to manage
136  * @stream with transport @tr.
137  *
138  * Returns: a new #GstRTSPStreamTransport
139  */
140 GstRTSPStreamTransport *
141 gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
142 {
143   GstRTSPStreamTransportPrivate *priv;
144   GstRTSPStreamTransport *trans;
145
146   g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
147   g_return_val_if_fail (tr != NULL, NULL);
148
149   trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL);
150   priv = trans->priv;
151   priv->stream = stream;
152   priv->transport = tr;
153
154   return trans;
155 }
156
157 /**
158  * gst_rtsp_stream_transport_get_stream:
159  * @trans: a #GstRTSPStreamTransport
160  *
161  * Get the #GstRTSPStream used when constructing @trans.
162  *
163  * Returns: (transfer none): the stream used when constructing @trans.
164  */
165 GstRTSPStream *
166 gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport * trans)
167 {
168   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
169
170   return trans->priv->stream;
171 }
172
173 /**
174  * gst_rtsp_stream_transport_set_callbacks:
175  * @trans: a #GstRTSPStreamTransport
176  * @send_rtp: (scope notified): a callback called when RTP should be sent
177  * @send_rtcp: (scope notified): a callback called when RTCP should be sent
178  * @user_data: user data passed to callbacks
179  * @notify: called with the user_data when no longer needed.
180  *
181  * Install callbacks that will be called when data for a stream should be sent
182  * to a client. This is usually used when sending RTP/RTCP over TCP.
183  */
184 void
185 gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans,
186     GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp,
187     gpointer user_data, GDestroyNotify notify)
188 {
189   GstRTSPStreamTransportPrivate *priv;
190
191   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
192
193   priv = trans->priv;
194
195   priv->send_rtp = send_rtp;
196   priv->send_rtcp = send_rtcp;
197   if (priv->notify)
198     priv->notify (priv->user_data);
199   priv->user_data = user_data;
200   priv->notify = notify;
201 }
202
203 /**
204  * gst_rtsp_stream_transport_set_keepalive:
205  * @trans: a #GstRTSPStreamTransport
206  * @keep_alive: a callback called when the receiver is active
207  * @user_data: user data passed to callback
208  * @notify: called with the user_data when no longer needed.
209  *
210  * Install callbacks that will be called when RTCP packets are received from the
211  * receiver of @trans.
212  */
213 void
214 gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
215     GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify)
216 {
217   GstRTSPStreamTransportPrivate *priv;
218
219   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
220
221   priv = trans->priv;
222
223   priv->keep_alive = keep_alive;
224   if (priv->ka_notify)
225     priv->ka_notify (priv->ka_user_data);
226   priv->ka_user_data = user_data;
227   priv->ka_notify = notify;
228 }
229
230
231 /**
232  * gst_rtsp_stream_transport_set_transport:
233  * @trans: a #GstRTSPStreamTransport
234  * @tr: (transfer full): a client #GstRTSPTransport
235  *
236  * Set @tr as the client transport. This function takes ownership of the
237  * passed @tr.
238  */
239 void
240 gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
241     GstRTSPTransport * tr)
242 {
243   GstRTSPStreamTransportPrivate *priv;
244
245   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
246   g_return_if_fail (tr != NULL);
247
248   priv = trans->priv;
249
250   /* keep track of the transports in the stream. */
251   if (priv->transport)
252     gst_rtsp_transport_free (priv->transport);
253   priv->transport = tr;
254 }
255
256 /**
257  * gst_rtsp_stream_transport_get_transport:
258  * @trans: a #GstRTSPStreamTransport
259  *
260  * Get the transport configured in @trans.
261  *
262  * Returns: (transfer none): the transport configured in @trans. It remains
263  *     valid for as long as @trans is valid.
264  */
265 const GstRTSPTransport *
266 gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans)
267 {
268   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
269
270   return trans->priv->transport;
271 }
272
273 /**
274  * gst_rtsp_stream_transport_set_url:
275  * @trans: a #GstRTSPStreamTransport
276  * @url: (transfer none): a client #GstRTSPUrl
277  *
278  * Set @url as the client url.
279  */
280 void
281 gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport * trans,
282     const GstRTSPUrl * url)
283 {
284   GstRTSPStreamTransportPrivate *priv;
285
286   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
287
288   priv = trans->priv;
289
290   /* keep track of the transports in the stream. */
291   if (priv->url)
292     gst_rtsp_url_free (priv->url);
293   priv->url = (url ? gst_rtsp_url_copy (url) : NULL);
294 }
295
296 /**
297  * gst_rtsp_stream_transport_get_url:
298  * @trans: a #GstRTSPStreamTransport
299  *
300  * Get the url configured in @trans.
301  *
302  * Returns: (transfer none): the url configured in @trans. It remains
303  *     valid for as long as @trans is valid.
304  */
305 const GstRTSPUrl *
306 gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans)
307 {
308   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
309
310   return trans->priv->url;
311 }
312
313  /**
314  * gst_rtsp_stream_transport_get_rtpinfo:
315  * @trans: a #GstRTSPStreamTransport
316  * @start_time: a star time
317  *
318  * Get the RTPInfo string for @trans and @start_time.
319  *
320  * Returns: the RTPInfo string for @trans and @start_time. g_free() after
321  * usage.
322  */
323 gchar *
324 gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans,
325     GstClockTime start_time)
326 {
327   GstRTSPStreamTransportPrivate *priv;
328   gchar *url_str;
329   GString *rtpinfo;
330   guint rtptime, seq;
331
332   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
333
334   priv = trans->priv;
335
336   if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, NULL))
337     return NULL;
338
339   rtpinfo = g_string_new ("");
340
341   url_str = gst_rtsp_url_get_request_uri (trans->priv->url);
342   g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u",
343       url_str, seq, rtptime);
344   g_free (url_str);
345
346   return g_string_free (rtpinfo, FALSE);
347 }
348
349 /**
350  * gst_rtsp_stream_transport_set_active:
351  * @trans: a #GstRTSPStreamTransport
352  * @active: new state of @trans
353  *
354  * Activate or deactivate datatransfer configured in @trans.
355  *
356  * Returns: %TRUE when the state was changed.
357  */
358 gboolean
359 gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport * trans,
360     gboolean active)
361 {
362   GstRTSPStreamTransportPrivate *priv;
363   gboolean res;
364
365   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
366
367   priv = trans->priv;
368
369   if (priv->active == active)
370     return FALSE;
371
372   if (active)
373     res = gst_rtsp_stream_add_transport (priv->stream, trans);
374   else
375     res = gst_rtsp_stream_remove_transport (priv->stream, trans);
376
377   if (res)
378     priv->active = active;
379
380   return res;
381 }
382
383 /**
384  * gst_rtsp_stream_transport_set_timed_out:
385  * @trans: a #GstRTSPStreamTransport
386  * @timedout: timed out value
387  *
388  * Set the timed out state of @trans to @timedout
389  */
390 void
391 gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport * trans,
392     gboolean timedout)
393 {
394   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
395
396   trans->priv->timed_out = timedout;
397 }
398
399 /**
400  * gst_rtsp_stream_transport_is_timed_out:
401  * @trans: a #GstRTSPStreamTransport
402  *
403  * Check if @trans is timed out.
404  *
405  * Returns: %TRUE if @trans timed out.
406  */
407 gboolean
408 gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport * trans)
409 {
410   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
411
412   return trans->priv->timed_out;
413 }
414
415 /**
416  * gst_rtsp_stream_transport_send_rtp:
417  * @trans: a #GstRTSPStreamTransport
418  * @buffer: a #GstBuffer
419  *
420  * Send @buffer to the installed RTP callback for @trans.
421  *
422  * Returns: %TRUE on success
423  */
424 gboolean
425 gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans,
426     GstBuffer * buffer)
427 {
428   GstRTSPStreamTransportPrivate *priv;
429   gboolean res = FALSE;
430
431   priv = trans->priv;
432
433   if (priv->send_rtp)
434     res =
435         priv->send_rtp (buffer, priv->transport->interleaved.min,
436         priv->user_data);
437
438   return res;
439 }
440
441 /**
442  * gst_rtsp_stream_transport_send_rtcp:
443  * @trans: a #GstRTSPStreamTransport
444  * @buffer: a #GstBuffer
445  *
446  * Send @buffer to the installed RTCP callback for @trans.
447  *
448  * Returns: %TRUE on success
449  */
450 gboolean
451 gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans,
452     GstBuffer * buffer)
453 {
454   GstRTSPStreamTransportPrivate *priv;
455   gboolean res = FALSE;
456
457   priv = trans->priv;
458
459   if (priv->send_rtcp)
460     res =
461         priv->send_rtcp (buffer, priv->transport->interleaved.max,
462         priv->user_data);
463
464   return res;
465 }
466
467 /**
468  * gst_rtsp_stream_transport_keep_alive:
469  * @trans: a #GstRTSPStreamTransport
470  *
471  * Signal the installed keep_alive callback for @trans.
472  */
473 void
474 gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans)
475 {
476   GstRTSPStreamTransportPrivate *priv;
477
478   priv = trans->priv;
479
480   if (priv->keep_alive)
481     priv->keep_alive (priv->ka_user_data);
482 }