2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
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.
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.
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.
20 #include "rtsp-media.h"
22 #define DEFAULT_SHARED FALSE
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);
37 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
40 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
42 GObjectClass *gobject_class;
44 gobject_class = G_OBJECT_CLASS (klass);
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;
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));
56 gst_rtsp_media_init (GstRTSPMedia * media)
58 media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
62 gst_rtsp_media_stream_free (GstRTSPMediaStream *stream)
67 gst_rtsp_media_finalize (GObject * obj)
72 media = GST_RTSP_MEDIA (obj);
74 for (i = 0; i < media->streams->len; i++) {
75 GstRTSPMediaStream *stream;
77 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
79 gst_rtsp_media_stream_free (stream);
81 g_array_free (media->streams, TRUE);
83 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
87 gst_rtsp_media_get_property (GObject *object, guint propid,
88 GValue *value, GParamSpec *pspec)
90 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
94 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
97 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
102 gst_rtsp_media_set_property (GObject *object, guint propid,
103 const GValue *value, GParamSpec *pspec)
105 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
109 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
112 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
117 * gst_rtsp_media_new:
119 * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
120 * element to produde RTP data for one or more related (audio/video/..)
123 * Returns: a new #GstRTSPMedia object.
126 gst_rtsp_media_new (void)
128 GstRTSPMedia *result;
130 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
136 * gst_rtsp_media_set_shared:
137 * @media: a #GstRTSPMedia
138 * @shared: the new value
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
145 gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared)
147 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
149 media->shared = shared;
153 * gst_rtsp_media_is_shared:
154 * @media: a #GstRTSPMedia
156 * Check if the pipeline for @media can be shared between multiple clients.
158 * Returns: %TRUE if the media can be shared between clients.
161 gst_rtsp_media_is_shared (GstRTSPMedia *media)
163 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
165 return media->shared;
169 * gst_rtsp_media_n_streams:
170 * @media: a #GstRTSPMedia
172 * Get the number of streams in this media.
174 * Returns: The number of streams.
177 gst_rtsp_media_n_streams (GstRTSPMedia *media)
179 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
181 return media->streams->len;
185 * gst_rtsp_media_get_stream:
186 * @media: a #GstRTSPMedia
187 * @idx: the stream index
189 * Retrieve the stream with index @idx from @media.
191 * Returns: the #GstRTSPMediaStream at index @idx.
194 gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx)
196 GstRTSPMediaStream *res;
198 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
199 g_return_val_if_fail (idx < media->streams->len, NULL);
201 res = g_array_index (media->streams, GstRTSPMediaStream *, idx);
206 /* Allocate the udp ports and sockets */
208 alloc_udp_ports (GstRTSPMediaStream * stream)
210 GstStateChangeReturn ret;
211 GstElement *udpsrc0, *udpsrc1;
212 GstElement *udpsink0, *udpsink1;
213 gint tmp_rtp, tmp_rtcp;
215 gint rtpport, rtcpport, sockfd;
223 /* Start with random port */
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 */
229 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
231 goto no_udp_protocol;
232 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
234 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
235 if (ret == GST_STATE_CHANGE_FAILURE) {
241 gst_element_set_state (udpsrc0, GST_STATE_NULL);
242 gst_object_unref (udpsrc0);
246 goto no_udp_protocol;
249 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
251 /* check if port is even */
252 if ((tmp_rtp & 1) != 0) {
253 /* port not even, close and allocate another */
257 gst_element_set_state (udpsrc0, GST_STATE_NULL);
258 gst_object_unref (udpsrc0);
264 /* allocate port+1 for RTCP now */
265 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
267 goto no_udp_rtcp_protocol;
270 tmp_rtcp = tmp_rtp + 1;
271 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
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) {
280 gst_element_set_state (udpsrc0, GST_STATE_NULL);
281 gst_object_unref (udpsrc0);
283 gst_element_set_state (udpsrc1, GST_STATE_NULL);
284 gst_object_unref (udpsrc1);
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);
294 /* this should not happen... */
295 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
298 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
300 goto no_udp_protocol;
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);
306 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
308 goto no_udp_protocol;
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);
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;
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);
342 no_udp_rtcp_protocol:
353 gst_element_set_state (udpsrc0, GST_STATE_NULL);
354 gst_object_unref (udpsrc0);
357 gst_element_set_state (udpsrc1, GST_STATE_NULL);
358 gst_object_unref (udpsrc1);
361 gst_element_set_state (udpsink0, GST_STATE_NULL);
362 gst_object_unref (udpsink0);
365 gst_element_set_state (udpsink1, GST_STATE_NULL);
366 gst_object_unref (udpsink1);
373 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
378 gst_caps_unref (stream->caps);
379 if ((stream->caps = GST_PAD_CAPS (pad)))
380 gst_caps_ref (stream->caps);
382 capsstr = gst_caps_to_string (stream->caps);
383 g_message ("stream %p received caps %s", stream, capsstr);
387 /* prepare the pipeline objects to handle @stream in @media */
389 setup_stream (GstRTSPMediaStream *stream, GstRTSPMedia *media)
394 alloc_udp_ports (stream);
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]);
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);
405 name = g_strdup_printf ("send_rtp_src_%d", stream->idx);
406 stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, 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);
411 name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx);
412 stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name);
415 /* link the RTP pad to the session manager */
416 gst_pad_link (stream->srcpad, stream->send_rtp_sink);
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);
429 /* we set and keep these to playing so that they don't cause NO_PREROLL return
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);
436 /* be notified of caps changes */
437 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
438 (GCallback) caps_notify, stream);
440 stream->prepared = TRUE;
446 * gst_rtsp_media_prepare:
447 * @obj: a #GstRTSPMedia
449 * Prepare @media for streaming. This function will create the pipeline and
450 * other objects to manage the streaming.
452 * Returns: %TRUE on success.
455 gst_rtsp_media_prepare (GstRTSPMedia *media)
457 GstStateChangeReturn ret;
463 g_message ("preparing media %p", media);
465 media->pipeline = gst_pipeline_new ("media-pipeline");
467 gst_bin_add (GST_BIN_CAST (media->pipeline), media->element);
469 media->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
471 /* add stuf to the bin */
472 gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
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;
479 stream = gst_rtsp_media_get_stream (media, i);
481 setup_stream (stream, media);
484 /* first go to PAUSED */
485 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
488 case GST_STATE_CHANGE_SUCCESS:
490 case GST_STATE_CHANGE_ASYNC:
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);
497 case GST_STATE_CHANGE_FAILURE:
501 /* now wait for all pads to be prerolled */
502 ret = gst_element_get_state (media->pipeline, NULL, NULL, -1);
504 /* and back to PAUSED for live pipelines */
505 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
507 n_streams = gst_rtsp_media_n_streams (media);
508 for (i = 0; i < n_streams; i++) {
509 GstRTSPMediaStream *stream;
511 stream = gst_rtsp_media_get_stream (media, i);
513 gst_element_set_locked_state (stream->udpsrc[0], FALSE);
514 gst_element_set_locked_state (stream->udpsrc[1], FALSE);
517 g_message ("object %p is prerolled", media);
518 media->prepared = TRUE;
530 g_message ("state change failed for media %p", media);
536 gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct)
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);
542 g_message ("adding %s:%d", ct->destination, ct->client_port.min);
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);
551 gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct)
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);
557 g_message ("removing %s:%d", ct->destination, ct->client_port.min);
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);
566 * gst_rtsp_media_play:
567 * @media: a #GstRTSPMedia
569 * Tell the @media to start playing and streaming to the client.
571 * Returns: a #GstStateChangeReturn
574 gst_rtsp_media_play (GstRTSPMedia *media)
576 GstStateChangeReturn ret;
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);
581 g_message ("playing");
582 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
588 * gst_rtsp_media_pause:
589 * @media: a #GstRTSPMedia
591 * Tell the @media to pause.
593 * Returns: a #GstStateChangeReturn
596 gst_rtsp_media_pause (GstRTSPMedia *media)
598 GstStateChangeReturn ret;
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);
603 g_message ("paused");
604 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
610 * gst_rtsp_media_stop:
611 * @media: a #GstRTSPMedia
613 * Tell the @media to stop playing. After this call the media
614 * cannot be played or paused anymore
616 * Returns: a #GstStateChangeReturn
619 gst_rtsp_media_stop (GstRTSPMedia *media)
621 GstStateChangeReturn ret;
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);
627 ret = gst_element_set_state (media->pipeline, GST_STATE_NULL);