Fix some leaks and change default port
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "rtsp-media.h"
21
22 #define DEFAULT_SHARED         FALSE
23
24 enum
25 {
26   PROP_0,
27   PROP_SHARED,
28   PROP_LAST
29 };
30
31 static void gst_rtsp_media_get_property (GObject *object, guint propid,
32     GValue *value, GParamSpec *pspec);
33 static void gst_rtsp_media_set_property (GObject *object, guint propid,
34     const GValue *value, GParamSpec *pspec);
35 static void gst_rtsp_media_finalize (GObject * obj);
36
37 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
38
39 static void
40 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
41 {
42   GObjectClass *gobject_class;
43
44   gobject_class = G_OBJECT_CLASS (klass);
45
46   gobject_class->get_property = gst_rtsp_media_get_property;
47   gobject_class->set_property = gst_rtsp_media_set_property;
48   gobject_class->finalize = gst_rtsp_media_finalize;
49
50   g_object_class_install_property (gobject_class, PROP_SHARED,
51       g_param_spec_boolean ("shared", "Shared", "If this media pipeline can be shared",
52           DEFAULT_SHARED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
53 }
54
55 static void
56 gst_rtsp_media_init (GstRTSPMedia * media)
57 {
58   media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
59 }
60
61 static void
62 gst_rtsp_media_stream_free (GstRTSPMediaStream *stream)
63 {
64 }
65
66 static void
67 gst_rtsp_media_finalize (GObject * obj)
68 {
69   GstRTSPMedia *media;
70   guint i;
71
72   media = GST_RTSP_MEDIA (obj);
73
74   for (i = 0; i < media->streams->len; i++) {
75     GstRTSPMediaStream *stream;
76
77     stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
78
79     gst_rtsp_media_stream_free (stream);
80   }
81   g_array_free (media->streams, TRUE);
82
83   G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
84 }
85
86 static void
87 gst_rtsp_media_get_property (GObject *object, guint propid,
88     GValue *value, GParamSpec *pspec)
89 {
90   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
91
92   switch (propid) {
93     case PROP_SHARED:
94       g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
95       break;
96     default:
97       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
98   }
99 }
100
101 static void
102 gst_rtsp_media_set_property (GObject *object, guint propid,
103     const GValue *value, GParamSpec *pspec)
104 {
105   GstRTSPMedia *media = GST_RTSP_MEDIA (object);
106
107   switch (propid) {
108     case PROP_SHARED:
109       gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
110       break;
111     default:
112       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
113   }
114 }
115
116 /**
117  * gst_rtsp_media_new:
118  *
119  * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
120  * element to produde RTP data for one or more related (audio/video/..) 
121  * streams.
122  *
123  * Returns: a new #GstRTSPMedia object.
124  */
125 GstRTSPMedia *
126 gst_rtsp_media_new (void)
127 {
128   GstRTSPMedia *result;
129
130   result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
131
132   return result;
133 }
134
135 /**
136  * gst_rtsp_media_set_shared:
137  * @media: a #GstRTSPMedia
138  * @shared: the new value
139  *
140  * Set or unset if the pipeline for @media can be shared will multiple clients.
141  * When @shared is %TRUE, client requests for this media will share the media
142  * pipeline.
143  */
144 void
145 gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared)
146 {
147   g_return_if_fail (GST_IS_RTSP_MEDIA (media));
148
149   media->shared = shared;
150 }
151
152 /**
153  * gst_rtsp_media_is_shared:
154  * @media: a #GstRTSPMedia
155  *
156  * Check if the pipeline for @media can be shared between multiple clients.
157  *
158  * Returns: %TRUE if the media can be shared between clients.
159  */
160 gboolean
161 gst_rtsp_media_is_shared (GstRTSPMedia *media)
162 {
163   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
164
165   return media->shared;
166 }
167
168 /**
169  * gst_rtsp_media_n_streams:
170  * @media: a #GstRTSPMedia
171  *
172  * Get the number of streams in this media.
173  *
174  * Returns: The number of streams.
175  */
176 guint
177 gst_rtsp_media_n_streams (GstRTSPMedia *media)
178 {
179   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
180
181   return media->streams->len;
182 }
183
184 /**
185  * gst_rtsp_media_get_stream:
186  * @media: a #GstRTSPMedia
187  * @idx: the stream index
188  *
189  * Retrieve the stream with index @idx from @media.
190  *
191  * Returns: the #GstRTSPMediaStream at index @idx.
192  */
193 GstRTSPMediaStream *
194 gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx)
195 {
196   GstRTSPMediaStream *res;
197   
198   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
199   g_return_val_if_fail (idx < media->streams->len, NULL);
200
201   res = g_array_index (media->streams, GstRTSPMediaStream *, idx);
202
203   return res;
204 }
205
206 /* Allocate the udp ports and sockets */
207 static gboolean
208 alloc_udp_ports (GstRTSPMediaStream * stream)
209 {
210   GstStateChangeReturn ret;
211   GstElement *udpsrc0, *udpsrc1;
212   GstElement *udpsink0, *udpsink1;
213   gint tmp_rtp, tmp_rtcp;
214   guint count;
215   gint rtpport, rtcpport, sockfd;
216
217   udpsrc0 = NULL;
218   udpsrc1 = NULL;
219   udpsink0 = NULL;
220   udpsink1 = NULL;
221   count = 0;
222
223   /* Start with random port */
224   tmp_rtp = 0;
225
226   /* try to allocate 2 UDP ports, the RTP port should be an even
227    * number and the RTCP port should be the next (uneven) port */
228 again:
229   udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
230   if (udpsrc0 == NULL)
231     goto no_udp_protocol;
232   g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
233
234   ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
235   if (ret == GST_STATE_CHANGE_FAILURE) {
236     if (tmp_rtp != 0) {
237       tmp_rtp += 2;
238       if (++count > 20)
239         goto no_ports;
240
241       gst_element_set_state (udpsrc0, GST_STATE_NULL);
242       gst_object_unref (udpsrc0);
243
244       goto again;
245     }
246     goto no_udp_protocol;
247   }
248
249   g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
250
251   /* check if port is even */
252   if ((tmp_rtp & 1) != 0) {
253     /* port not even, close and allocate another */
254     if (++count > 20)
255       goto no_ports;
256
257     gst_element_set_state (udpsrc0, GST_STATE_NULL);
258     gst_object_unref (udpsrc0);
259
260     tmp_rtp++;
261     goto again;
262   }
263
264   /* allocate port+1 for RTCP now */
265   udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
266   if (udpsrc1 == NULL)
267     goto no_udp_rtcp_protocol;
268
269   /* set port */
270   tmp_rtcp = tmp_rtp + 1;
271   g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
272
273   ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
274   /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
275   if (ret == GST_STATE_CHANGE_FAILURE) {
276
277     if (++count > 20)
278       goto no_ports;
279
280     gst_element_set_state (udpsrc0, GST_STATE_NULL);
281     gst_object_unref (udpsrc0);
282
283     gst_element_set_state (udpsrc1, GST_STATE_NULL);
284     gst_object_unref (udpsrc1);
285
286     tmp_rtp += 2;
287     goto again;
288   }
289
290   /* all fine, do port check */
291   g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
292   g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
293
294   /* this should not happen... */
295   if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
296     goto port_error;
297
298   udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
299   if (!udpsink0)
300     goto no_udp_protocol;
301
302   g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL);
303   g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL);
304   g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL);
305
306   udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
307   if (!udpsink1)
308     goto no_udp_protocol;
309
310   g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
311   g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL);
312   g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL);
313   g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
314   g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
315
316   /* we keep these elements, we configure all in configure_transport when the
317    * server told us to really use the UDP ports. */
318   stream->udpsrc[0] = gst_object_ref (udpsrc0);
319   stream->udpsrc[1] = gst_object_ref (udpsrc1);
320   stream->udpsink[0] = gst_object_ref (udpsink0);
321   stream->udpsink[1] = gst_object_ref (udpsink1);
322   stream->server_port.min = rtpport;
323   stream->server_port.max = rtcpport;
324
325   /* they are ours now */
326   gst_object_sink (udpsrc0);
327   gst_object_sink (udpsrc1);
328   gst_object_sink (udpsink0);
329   gst_object_sink (udpsink1);
330
331   return TRUE;
332
333   /* ERRORS */
334 no_udp_protocol:
335   {
336     goto cleanup;
337   }
338 no_ports:
339   {
340     goto cleanup;
341   }
342 no_udp_rtcp_protocol:
343   {
344     goto cleanup;
345   }
346 port_error:
347   {
348     goto cleanup;
349   }
350 cleanup:
351   {
352     if (udpsrc0) {
353       gst_element_set_state (udpsrc0, GST_STATE_NULL);
354       gst_object_unref (udpsrc0);
355     }
356     if (udpsrc1) {
357       gst_element_set_state (udpsrc1, GST_STATE_NULL);
358       gst_object_unref (udpsrc1);
359     }
360     if (udpsink0) {
361       gst_element_set_state (udpsink0, GST_STATE_NULL);
362       gst_object_unref (udpsink0);
363     }
364     if (udpsink1) {
365       gst_element_set_state (udpsink1, GST_STATE_NULL);
366       gst_object_unref (udpsink1);
367     }
368     return FALSE;
369   }
370 }
371
372 static void
373 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
374 {
375   gchar *capsstr;
376
377   if (stream->caps)
378     gst_caps_unref (stream->caps);
379   if ((stream->caps = GST_PAD_CAPS (pad)))
380     gst_caps_ref (stream->caps);
381
382   capsstr = gst_caps_to_string (stream->caps);
383   g_message ("stream %p received caps %s", stream, capsstr);
384   g_free (capsstr);
385 }
386
387 /* prepare the pipeline objects to handle @stream in @media */
388 static gboolean
389 setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media)
390 {
391   gchar *name;
392   GstPad *pad;
393
394   alloc_udp_ports (stream);
395
396   gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[0]);
397   gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[1]);
398   gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[0]);
399   gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[1]);
400
401   /* hook up the stream to the RTP session elements. */
402   name = g_strdup_printf ("send_rtp_sink_%d", stream->idx);
403   stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
404   g_free (name);
405   name = g_strdup_printf ("send_rtp_src_%d", stream->idx);
406   stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name);
407   g_free (name);
408   name = g_strdup_printf ("send_rtcp_src_%d", stream->idx);
409   stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name);
410   g_free (name);
411   name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx);
412   stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name);
413   g_free (name);
414
415   /* link the RTP pad to the session manager */
416   gst_pad_link (stream->srcpad, stream->send_rtp_sink);
417
418   /* link udp elements */
419   pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
420   gst_pad_link (stream->send_rtp_src, pad);
421   gst_object_unref (pad);
422   pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
423   gst_pad_link (stream->send_rtcp_src, pad);
424   gst_object_unref (pad);
425   pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
426   gst_pad_link (pad, stream->recv_rtcp_sink);
427   gst_object_unref (pad);
428
429   /* we set and keep these to playing so that they don't cause NO_PREROLL return
430    * values */
431   gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING);
432   gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING);
433   gst_element_set_locked_state (stream->udpsrc[0], TRUE);
434   gst_element_set_locked_state (stream->udpsrc[1], TRUE);
435  
436   /* be notified of caps changes */
437   stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
438                   (GCallback) caps_notify, stream);
439
440   stream->prepared = TRUE;
441
442   return TRUE;
443 }
444
445 /**
446  * gst_rtsp_media_prepare:
447  * @obj: a #GstRTSPMedia
448  *
449  * Prepare @media for streaming. This function will create the pipeline and
450  * other objects to manage the streaming.
451  *
452  * Returns: %TRUE on success.
453  */
454 gboolean
455 gst_rtsp_media_prepare (GstRTSPMedia *media)
456 {
457   GstStateChangeReturn ret;
458   guint i, n_streams;
459
460   if (media->prepared)
461     goto was_prepared;
462
463   g_message ("preparing media %p", media);
464
465   media->pipeline = gst_pipeline_new ("media-pipeline");
466
467   gst_bin_add (GST_BIN_CAST (media->pipeline), media->element);
468
469   media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
470
471   /* add stuf to the bin */
472   gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
473
474   /* link streams we already have */
475   n_streams = gst_rtsp_media_n_streams (media);
476   for (i = 0; i < n_streams; i++) {
477     GstRTSPMediaStream *stream;
478
479     stream = gst_rtsp_media_get_stream (media, i);
480
481     setup_stream (stream, media);
482   }
483
484   /* first go to PAUSED */
485   ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
486
487   switch (ret) {
488     case GST_STATE_CHANGE_SUCCESS:
489       break;
490     case GST_STATE_CHANGE_ASYNC:
491       break;
492     case GST_STATE_CHANGE_NO_PREROLL:
493       /* we need to go to PLAYING */
494       g_message ("live media %p", media);
495       ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
496       break;
497     case GST_STATE_CHANGE_FAILURE:
498       goto state_failed;
499   }
500
501   /* now wait for all pads to be prerolled */
502   ret = gst_element_get_state (media->pipeline, NULL, NULL, -1);
503
504   /* and back to PAUSED for live pipelines */
505   ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
506
507   n_streams = gst_rtsp_media_n_streams (media);
508   for (i = 0; i < n_streams; i++) {
509     GstRTSPMediaStream *stream;
510
511     stream = gst_rtsp_media_get_stream (media, i);
512
513     gst_element_set_locked_state (stream->udpsrc[0], FALSE);
514     gst_element_set_locked_state (stream->udpsrc[1], FALSE);
515   }
516
517   g_message ("object %p is prerolled", media);
518   media->prepared = TRUE;
519
520   return TRUE;
521
522   /* OK */
523 was_prepared:
524   {
525     return TRUE;
526   }
527   /* ERRORS */
528 state_failed:
529   {
530     g_message ("state change failed for media %p", media);
531     return FALSE;
532   }
533 }
534
535 gboolean
536 gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct)
537 {
538   g_return_val_if_fail (stream != NULL, FALSE);
539   g_return_val_if_fail (ct != NULL, FALSE);
540   g_return_val_if_fail (stream->prepared, FALSE);
541
542   g_message ("adding %s:%d", ct->destination, ct->client_port.min);
543
544   g_signal_emit_by_name (stream->udpsink[0], "add", ct->destination, ct->client_port.min, NULL);
545   g_signal_emit_by_name (stream->udpsink[1], "add", ct->destination, ct->client_port.max, NULL);
546
547   return TRUE;
548 }
549
550 gboolean
551 gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct)
552 {
553   g_return_val_if_fail (stream != NULL, FALSE);
554   g_return_val_if_fail (ct != NULL, FALSE);
555   g_return_val_if_fail (stream->prepared, FALSE);
556
557   g_message ("removing %s:%d", ct->destination, ct->client_port.min);
558
559   g_signal_emit_by_name (stream->udpsink[0], "remove", ct->destination, ct->client_port.min, NULL);
560   g_signal_emit_by_name (stream->udpsink[1], "remove", ct->destination, ct->client_port.max, NULL);
561
562   return TRUE;
563 }
564
565 /**
566  * gst_rtsp_media_play:
567  * @media: a #GstRTSPMedia
568  *
569  * Tell the @media to start playing and streaming to the client.
570  *
571  * Returns: a #GstStateChangeReturn
572  */
573 GstStateChangeReturn
574 gst_rtsp_media_play (GstRTSPMedia *media)
575 {
576   GstStateChangeReturn ret;
577
578   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE);
579   g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE);
580
581   g_message ("playing");
582   ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
583
584   return ret;
585 }
586
587 /**
588  * gst_rtsp_media_pause:
589  * @media: a #GstRTSPMedia
590  *
591  * Tell the @media to pause.
592  *
593  * Returns: a #GstStateChangeReturn
594  */
595 GstStateChangeReturn
596 gst_rtsp_media_pause (GstRTSPMedia *media)
597 {
598   GstStateChangeReturn ret;
599
600   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE);
601   g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE);
602
603   g_message ("paused");
604   ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
605
606   return ret;
607 }
608
609 /**
610  * gst_rtsp_media_stop:
611  * @media: a #GstRTSPMedia
612  *
613  * Tell the @media to stop playing. After this call the media
614  * cannot be played or paused anymore
615  *
616  * Returns: a #GstStateChangeReturn
617  */
618 GstStateChangeReturn
619 gst_rtsp_media_stop (GstRTSPMedia *media)
620 {
621   GstStateChangeReturn ret;
622
623   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE);
624   g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE);
625
626   g_message ("stop");
627   ret = gst_element_set_state (media->pipeline, GST_STATE_NULL);
628
629   return ret;
630 }
631