session: improve RTP-Info
[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 RTP-Info string for @trans and @start_time.
319  *
320  * Returns: the RTPInfo string for @trans and @start_time or %NULL when
321  * the RTP-Info could not be determined. g_free() after 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, clock_rate;
331   GstClockTime running_time = GST_CLOCK_TIME_NONE;
332
333   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
334
335   priv = trans->priv;
336
337   if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, &clock_rate,
338           &running_time))
339     return NULL;
340
341   GST_DEBUG ("RTP time %u, seq %u, rate %u, running-time %" GST_TIME_FORMAT,
342       rtptime, seq, clock_rate, GST_TIME_ARGS (running_time));
343
344   if (GST_CLOCK_TIME_IS_VALID (running_time)
345       && GST_CLOCK_TIME_IS_VALID (start_time)) {
346     if (running_time > start_time) {
347       rtptime -=
348           gst_util_uint64_scale_int (running_time - start_time, clock_rate,
349           GST_SECOND);
350     } else {
351       rtptime +=
352           gst_util_uint64_scale_int (start_time - running_time, clock_rate,
353           GST_SECOND);
354     }
355   }
356   GST_DEBUG ("RTP time %u, for start-time %" GST_TIME_FORMAT,
357       rtptime, GST_TIME_ARGS (start_time));
358
359   rtpinfo = g_string_new ("");
360
361   url_str = gst_rtsp_url_get_request_uri (trans->priv->url);
362   g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u",
363       url_str, seq, rtptime);
364   g_free (url_str);
365
366   return g_string_free (rtpinfo, FALSE);
367 }
368
369 /**
370  * gst_rtsp_stream_transport_set_active:
371  * @trans: a #GstRTSPStreamTransport
372  * @active: new state of @trans
373  *
374  * Activate or deactivate datatransfer configured in @trans.
375  *
376  * Returns: %TRUE when the state was changed.
377  */
378 gboolean
379 gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport * trans,
380     gboolean active)
381 {
382   GstRTSPStreamTransportPrivate *priv;
383   gboolean res;
384
385   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
386
387   priv = trans->priv;
388
389   if (priv->active == active)
390     return FALSE;
391
392   if (active)
393     res = gst_rtsp_stream_add_transport (priv->stream, trans);
394   else
395     res = gst_rtsp_stream_remove_transport (priv->stream, trans);
396
397   if (res)
398     priv->active = active;
399
400   return res;
401 }
402
403 /**
404  * gst_rtsp_stream_transport_set_timed_out:
405  * @trans: a #GstRTSPStreamTransport
406  * @timedout: timed out value
407  *
408  * Set the timed out state of @trans to @timedout
409  */
410 void
411 gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport * trans,
412     gboolean timedout)
413 {
414   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
415
416   trans->priv->timed_out = timedout;
417 }
418
419 /**
420  * gst_rtsp_stream_transport_is_timed_out:
421  * @trans: a #GstRTSPStreamTransport
422  *
423  * Check if @trans is timed out.
424  *
425  * Returns: %TRUE if @trans timed out.
426  */
427 gboolean
428 gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport * trans)
429 {
430   g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
431
432   return trans->priv->timed_out;
433 }
434
435 /**
436  * gst_rtsp_stream_transport_send_rtp:
437  * @trans: a #GstRTSPStreamTransport
438  * @buffer: a #GstBuffer
439  *
440  * Send @buffer to the installed RTP callback for @trans.
441  *
442  * Returns: %TRUE on success
443  */
444 gboolean
445 gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans,
446     GstBuffer * buffer)
447 {
448   GstRTSPStreamTransportPrivate *priv;
449   gboolean res = FALSE;
450
451   priv = trans->priv;
452
453   if (priv->send_rtp)
454     res =
455         priv->send_rtp (buffer, priv->transport->interleaved.min,
456         priv->user_data);
457
458   return res;
459 }
460
461 /**
462  * gst_rtsp_stream_transport_send_rtcp:
463  * @trans: a #GstRTSPStreamTransport
464  * @buffer: a #GstBuffer
465  *
466  * Send @buffer to the installed RTCP callback for @trans.
467  *
468  * Returns: %TRUE on success
469  */
470 gboolean
471 gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans,
472     GstBuffer * buffer)
473 {
474   GstRTSPStreamTransportPrivate *priv;
475   gboolean res = FALSE;
476
477   priv = trans->priv;
478
479   if (priv->send_rtcp)
480     res =
481         priv->send_rtcp (buffer, priv->transport->interleaved.max,
482         priv->user_data);
483
484   return res;
485 }
486
487 /**
488  * gst_rtsp_stream_transport_keep_alive:
489  * @trans: a #GstRTSPStreamTransport
490  *
491  * Signal the installed keep_alive callback for @trans.
492  */
493 void
494 gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans)
495 {
496   GstRTSPStreamTransportPrivate *priv;
497
498   priv = trans->priv;
499
500   if (priv->keep_alive)
501     priv->keep_alive (priv->ka_user_data);
502 }