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.
23 #include <gst/app/gstappsrc.h>
24 #include <gst/app/gstappsink.h>
26 #include "rtsp-funnel.h"
27 #include "rtsp-media.h"
29 #define DEFAULT_SHARED FALSE
30 #define DEFAULT_REUSABLE FALSE
31 #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
32 //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
33 #define DEFAULT_EOS_SHUTDOWN FALSE
35 /* define to dump received RTCP packets */
56 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
57 #define GST_CAT_DEFAULT rtsp_media_debug
59 static GQuark ssrc_stream_map_key;
61 static void gst_rtsp_media_get_property (GObject * object, guint propid,
62 GValue * value, GParamSpec * pspec);
63 static void gst_rtsp_media_set_property (GObject * object, guint propid,
64 const GValue * value, GParamSpec * pspec);
65 static void gst_rtsp_media_finalize (GObject * obj);
67 static gpointer do_loop (GstRTSPMediaClass * klass);
68 static gboolean default_handle_message (GstRTSPMedia * media,
69 GstMessage * message);
70 static gboolean default_unprepare (GstRTSPMedia * media);
71 static void unlock_streams (GstRTSPMedia * media);
73 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
75 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
78 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
80 GObjectClass *gobject_class;
83 gobject_class = G_OBJECT_CLASS (klass);
85 gobject_class->get_property = gst_rtsp_media_get_property;
86 gobject_class->set_property = gst_rtsp_media_set_property;
87 gobject_class->finalize = gst_rtsp_media_finalize;
89 g_object_class_install_property (gobject_class, PROP_SHARED,
90 g_param_spec_boolean ("shared", "Shared",
91 "If this media pipeline can be shared", DEFAULT_SHARED,
92 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
94 g_object_class_install_property (gobject_class, PROP_REUSABLE,
95 g_param_spec_boolean ("reusable", "Reusable",
96 "If this media pipeline can be reused after an unprepare",
97 DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
99 g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
100 g_param_spec_flags ("protocols", "Protocols",
101 "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
102 DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
104 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
105 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
106 "Send an EOS event to the pipeline before unpreparing",
107 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
109 gst_rtsp_media_signals[SIGNAL_PREPARED] =
110 g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
111 G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
112 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
114 gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
115 g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
116 G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
117 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
119 gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
120 g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
121 G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
122 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
124 klass->context = g_main_context_new ();
125 klass->loop = g_main_loop_new (klass->context, TRUE);
127 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
129 klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
131 g_critical ("could not start bus thread: %s", error->message);
133 klass->handle_message = default_handle_message;
134 klass->unprepare = default_unprepare;
136 ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
138 gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL);
143 gst_rtsp_media_init (GstRTSPMedia * media)
145 media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
146 media->lock = g_mutex_new ();
147 media->cond = g_cond_new ();
149 media->shared = DEFAULT_SHARED;
150 media->reusable = DEFAULT_REUSABLE;
151 media->protocols = DEFAULT_PROTOCOLS;
152 media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
155 /* FIXME. this should be done in multiudpsink */
164 dest_compare (RTSPDestination * a, RTSPDestination * b)
166 if ((a->min == b->min) && (a->max == b->max)
167 && (strcmp (a->dest, b->dest) == 0))
173 static RTSPDestination *
174 create_destination (const gchar * dest, gint min, gint max)
176 RTSPDestination *res;
178 res = g_slice_new (RTSPDestination);
180 res->dest = g_strdup (dest);
188 free_destination (RTSPDestination * dest)
191 g_slice_free (RTSPDestination, dest);
195 gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans * trans)
197 if (trans->transport) {
198 gst_rtsp_transport_free (trans->transport);
199 trans->transport = NULL;
201 if (trans->rtpsource) {
202 g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL);
203 trans->rtpsource = NULL;
208 gst_rtsp_media_stream_free (GstRTSPMediaStream * stream)
211 g_object_unref (stream->session);
214 gst_caps_unref (stream->caps);
216 if (stream->send_rtp_sink)
217 gst_object_unref (stream->send_rtp_sink);
218 if (stream->send_rtp_src)
219 gst_object_unref (stream->send_rtp_src);
220 if (stream->send_rtcp_src)
221 gst_object_unref (stream->send_rtcp_src);
222 if (stream->recv_rtcp_sink)
223 gst_object_unref (stream->recv_rtcp_sink);
224 if (stream->recv_rtp_sink)
225 gst_object_unref (stream->recv_rtp_sink);
227 g_list_free (stream->transports);
229 g_list_foreach (stream->destinations, (GFunc) free_destination, NULL);
230 g_list_free (stream->destinations);
236 gst_rtsp_media_finalize (GObject * obj)
241 media = GST_RTSP_MEDIA (obj);
243 GST_INFO ("finalize media %p", media);
245 if (media->pipeline) {
246 unlock_streams (media);
247 gst_element_set_state (media->pipeline, GST_STATE_NULL);
248 gst_object_unref (media->pipeline);
251 for (i = 0; i < media->streams->len; i++) {
252 GstRTSPMediaStream *stream;
254 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
256 gst_rtsp_media_stream_free (stream);
258 g_array_free (media->streams, TRUE);
260 g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL);
261 g_list_free (media->dynamic);
264 g_source_destroy (media->source);
265 g_source_unref (media->source);
267 g_mutex_free (media->lock);
268 g_cond_free (media->cond);
270 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
274 gst_rtsp_media_get_property (GObject * object, guint propid,
275 GValue * value, GParamSpec * pspec)
277 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
281 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
284 g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
287 g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
289 case PROP_EOS_SHUTDOWN:
290 g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
293 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
298 gst_rtsp_media_set_property (GObject * object, guint propid,
299 const GValue * value, GParamSpec * pspec)
301 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
305 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
308 gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
311 gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
313 case PROP_EOS_SHUTDOWN:
314 gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
317 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
322 do_loop (GstRTSPMediaClass * klass)
324 GST_INFO ("enter mainloop");
325 g_main_loop_run (klass->loop);
326 GST_INFO ("exit mainloop");
332 collect_media_stats (GstRTSPMedia * media)
335 gint64 position, duration;
337 media->range.unit = GST_RTSP_RANGE_NPT;
339 if (media->is_live) {
340 media->range.min.type = GST_RTSP_TIME_NOW;
341 media->range.min.seconds = -1;
342 media->range.max.type = GST_RTSP_TIME_END;
343 media->range.max.seconds = -1;
345 /* get the position */
346 format = GST_FORMAT_TIME;
347 if (!gst_element_query_position (media->pipeline, &format, &position)) {
348 GST_INFO ("position query failed");
352 /* get the duration */
353 format = GST_FORMAT_TIME;
354 if (!gst_element_query_duration (media->pipeline, &format, &duration)) {
355 GST_INFO ("duration query failed");
359 GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
360 GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
362 if (position == -1) {
363 media->range.min.type = GST_RTSP_TIME_NOW;
364 media->range.min.seconds = -1;
366 media->range.min.type = GST_RTSP_TIME_SECONDS;
367 media->range.min.seconds = ((gdouble) position) / GST_SECOND;
369 if (duration == -1) {
370 media->range.max.type = GST_RTSP_TIME_END;
371 media->range.max.seconds = -1;
373 media->range.max.type = GST_RTSP_TIME_SECONDS;
374 media->range.max.seconds = ((gdouble) duration) / GST_SECOND;
380 * gst_rtsp_media_new:
382 * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
383 * element to produde RTP data for one or more related (audio/video/..)
386 * Returns: a new #GstRTSPMedia object.
389 gst_rtsp_media_new (void)
391 GstRTSPMedia *result;
393 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
399 * gst_rtsp_media_set_shared:
400 * @media: a #GstRTSPMedia
401 * @shared: the new value
403 * Set or unset if the pipeline for @media can be shared will multiple clients.
404 * When @shared is %TRUE, client requests for this media will share the media
408 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
410 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
412 media->shared = shared;
416 * gst_rtsp_media_is_shared:
417 * @media: a #GstRTSPMedia
419 * Check if the pipeline for @media can be shared between multiple clients.
421 * Returns: %TRUE if the media can be shared between clients.
424 gst_rtsp_media_is_shared (GstRTSPMedia * media)
426 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
428 return media->shared;
432 * gst_rtsp_media_set_reusable:
433 * @media: a #GstRTSPMedia
434 * @reusable: the new value
436 * Set or unset if the pipeline for @media can be reused after the pipeline has
440 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
442 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
444 media->reusable = reusable;
448 * gst_rtsp_media_is_reusable:
449 * @media: a #GstRTSPMedia
451 * Check if the pipeline for @media can be reused after an unprepare.
453 * Returns: %TRUE if the media can be reused
456 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
458 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
460 return media->reusable;
464 * gst_rtsp_media_set_protocols:
465 * @media: a #GstRTSPMedia
466 * @protocols: the new flags
468 * Configure the allowed lower transport for @media.
471 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
473 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
475 media->protocols = protocols;
479 * gst_rtsp_media_get_protocols:
480 * @media: a #GstRTSPMedia
482 * Get the allowed protocols of @media.
484 * Returns: a #GstRTSPLowerTrans
487 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
489 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
490 GST_RTSP_LOWER_TRANS_UNKNOWN);
492 return media->protocols;
496 * gst_rtsp_media_set_eos_shutdown:
497 * @media: a #GstRTSPMedia
498 * @eos_shutdown: the new value
500 * Set or unset if an EOS event will be sent to the pipeline for @media before
504 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
506 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
508 media->eos_shutdown = eos_shutdown;
512 * gst_rtsp_media_is_eos_shutdown:
513 * @media: a #GstRTSPMedia
515 * Check if the pipeline for @media will send an EOS down the pipeline before
518 * Returns: %TRUE if the media will send EOS before unpreparing.
521 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
523 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
525 return media->eos_shutdown;
529 * gst_rtsp_media_set_auth:
530 * @media: a #GstRTSPMedia
531 * @auth: a #GstRTSPAuth
533 * configure @auth to be used as the authentication manager of @media.
536 gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
540 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
549 g_object_unref (old);
554 * gst_rtsp_media_get_auth:
555 * @media: a #GstRTSPMedia
557 * Get the #GstRTSPAuth used as the authentication manager of @media.
559 * Returns: the #GstRTSPAuth of @media. g_object_unref() after
563 gst_rtsp_media_get_auth (GstRTSPMedia * media)
567 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
569 if ((result = media->auth))
570 g_object_ref (result);
577 * gst_rtsp_media_n_streams:
578 * @media: a #GstRTSPMedia
580 * Get the number of streams in this media.
582 * Returns: The number of streams.
585 gst_rtsp_media_n_streams (GstRTSPMedia * media)
587 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
589 return media->streams->len;
593 * gst_rtsp_media_get_stream:
594 * @media: a #GstRTSPMedia
595 * @idx: the stream index
597 * Retrieve the stream with index @idx from @media.
599 * Returns: the #GstRTSPMediaStream at index @idx or %NULL when a stream with
600 * that index did not exist.
603 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
605 GstRTSPMediaStream *res;
607 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
609 if (idx < media->streams->len)
610 res = g_array_index (media->streams, GstRTSPMediaStream *, idx);
618 * gst_rtsp_media_get_range_string:
619 * @media: a #GstRTSPMedia
620 * @play: for the PLAY request
622 * Get the current range as a string.
624 * Returns: The range as a string, g_free() after usage.
627 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
630 GstRTSPTimeRange range;
633 range = media->range;
635 if (!play && media->active > 0) {
636 range.min.type = GST_RTSP_TIME_NOW;
637 range.min.seconds = -1;
640 result = gst_rtsp_range_to_string (&range);
646 * gst_rtsp_media_seek:
647 * @media: a #GstRTSPMedia
648 * @range: a #GstRTSPTimeRange
650 * Seek the pipeline to @range.
652 * Returns: %TRUE on success.
655 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
660 GstSeekType start_type, stop_type;
662 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
663 g_return_val_if_fail (range != NULL, FALSE);
665 if (range->unit != GST_RTSP_RANGE_NPT)
668 /* depends on the current playing state of the pipeline. We might need to
669 * queue this until we get EOS. */
670 flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
672 start_type = stop_type = GST_SEEK_TYPE_NONE;
674 switch (range->min.type) {
675 case GST_RTSP_TIME_NOW:
678 case GST_RTSP_TIME_SECONDS:
679 /* only seek when something changed */
680 if (media->range.min.seconds == range->min.seconds) {
683 start = range->min.seconds * GST_SECOND;
684 start_type = GST_SEEK_TYPE_SET;
687 case GST_RTSP_TIME_END:
691 switch (range->max.type) {
692 case GST_RTSP_TIME_SECONDS:
693 /* only seek when something changed */
694 if (media->range.max.seconds == range->max.seconds) {
697 stop = range->max.seconds * GST_SECOND;
698 stop_type = GST_SEEK_TYPE_SET;
701 case GST_RTSP_TIME_END:
703 stop_type = GST_SEEK_TYPE_SET;
705 case GST_RTSP_TIME_NOW:
710 if (start != -1 || stop != -1) {
711 GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
712 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
714 res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME,
715 flags, start_type, start, stop_type, stop);
717 /* and block for the seek to complete */
718 GST_INFO ("done seeking %d", res);
719 gst_element_get_state (media->pipeline, NULL, NULL, -1);
720 GST_INFO ("prerolled again");
722 collect_media_stats (media);
724 GST_INFO ("no seek needed");
733 GST_WARNING ("seek unit %d not supported", range->unit);
738 GST_WARNING ("weird range type %d not supported", range->min.type);
744 * gst_rtsp_media_stream_rtp:
745 * @stream: a #GstRTSPMediaStream
746 * @buffer: a #GstBuffer
748 * Handle an RTP buffer for the stream. This method is usually called when a
749 * message has been received from a client using the TCP transport.
751 * This function takes ownership of @buffer.
753 * Returns: a GstFlowReturn.
756 gst_rtsp_media_stream_rtp (GstRTSPMediaStream * stream, GstBuffer * buffer)
760 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer);
766 * gst_rtsp_media_stream_rtcp:
767 * @stream: a #GstRTSPMediaStream
768 * @buffer: a #GstBuffer
770 * Handle an RTCP buffer for the stream. This method is usually called when a
771 * message has been received from a client using the TCP transport.
773 * This function takes ownership of @buffer.
775 * Returns: a GstFlowReturn.
778 gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer)
782 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer);
787 /* Allocate the udp ports and sockets */
789 alloc_udp_ports (GstRTSPMedia * media, GstRTSPMediaStream * stream)
791 GstStateChangeReturn ret;
792 GstElement *udpsrc0, *udpsrc1;
793 GstElement *udpsink0, *udpsink1;
794 gint tmp_rtp, tmp_rtcp;
796 gint rtpport, rtcpport, sockfd;
805 /* Start with random port */
809 host = "udp://[::0]";
811 host = "udp://0.0.0.0";
813 /* try to allocate 2 UDP ports, the RTP port should be an even
814 * number and the RTCP port should be the next (uneven) port */
816 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL);
818 goto no_udp_protocol;
819 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
821 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
822 if (ret == GST_STATE_CHANGE_FAILURE) {
828 gst_element_set_state (udpsrc0, GST_STATE_NULL);
829 gst_object_unref (udpsrc0);
833 goto no_udp_protocol;
836 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
838 /* check if port is even */
839 if ((tmp_rtp & 1) != 0) {
840 /* port not even, close and allocate another */
844 gst_element_set_state (udpsrc0, GST_STATE_NULL);
845 gst_object_unref (udpsrc0);
851 /* allocate port+1 for RTCP now */
852 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL);
854 goto no_udp_rtcp_protocol;
857 tmp_rtcp = tmp_rtp + 1;
858 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
860 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
861 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
862 if (ret == GST_STATE_CHANGE_FAILURE) {
867 gst_element_set_state (udpsrc0, GST_STATE_NULL);
868 gst_object_unref (udpsrc0);
870 gst_element_set_state (udpsrc1, GST_STATE_NULL);
871 gst_object_unref (udpsrc1);
877 /* all fine, do port check */
878 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
879 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
881 /* this should not happen... */
882 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
885 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
887 goto no_udp_protocol;
889 g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL);
890 g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL);
891 g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL);
893 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
895 goto no_udp_protocol;
897 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
898 "send-duplicates")) {
899 g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
900 g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
901 stream->filter_duplicates = FALSE;
903 GST_WARNING ("multiudpsink version found without send-duplicates property");
904 stream->filter_duplicates = TRUE;
907 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
909 g_object_set (G_OBJECT (udpsink0), "buffer-size", 0x80000, NULL);
911 GST_WARNING ("multiudpsink version found without buffer-size property");
914 g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
915 g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL);
916 g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL);
917 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
918 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
920 g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
921 g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL);
922 g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL);
923 g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL);
925 /* we keep these elements, we configure all in configure_transport when the
926 * server told us to really use the UDP ports. */
927 stream->udpsrc[0] = udpsrc0;
928 stream->udpsrc[1] = udpsrc1;
929 stream->udpsink[0] = udpsink0;
930 stream->udpsink[1] = udpsink1;
931 stream->server_port.min = rtpport;
932 stream->server_port.max = rtcpport;
945 no_udp_rtcp_protocol:
956 gst_element_set_state (udpsrc0, GST_STATE_NULL);
957 gst_object_unref (udpsrc0);
960 gst_element_set_state (udpsrc1, GST_STATE_NULL);
961 gst_object_unref (udpsrc1);
964 gst_element_set_state (udpsink0, GST_STATE_NULL);
965 gst_object_unref (udpsink0);
968 gst_element_set_state (udpsink1, GST_STATE_NULL);
969 gst_object_unref (udpsink1);
975 /* executed from streaming thread */
977 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
980 GstCaps *newcaps, *oldcaps;
982 if ((newcaps = GST_PAD_CAPS (pad)))
983 gst_caps_ref (newcaps);
985 oldcaps = stream->caps;
986 stream->caps = newcaps;
989 gst_caps_unref (oldcaps);
991 capsstr = gst_caps_to_string (newcaps);
992 GST_INFO ("stream %p received caps %p, %s", stream, newcaps, capsstr);
997 dump_structure (const GstStructure * s)
1001 sstr = gst_structure_to_string (s);
1002 GST_INFO ("structure: %s", sstr);
1006 static GstRTSPMediaTrans *
1007 find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from)
1010 GstRTSPMediaTrans *result = NULL;
1015 if (rtcp_from == NULL)
1018 tmp = g_strrstr (rtcp_from, ":");
1022 port = atoi (tmp + 1);
1023 dest = g_strndup (rtcp_from, tmp - rtcp_from);
1025 GST_INFO ("finding %s:%d", dest, port);
1027 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
1028 GstRTSPMediaTrans *trans = walk->data;
1031 min = trans->transport->client_port.min;
1032 max = trans->transport->client_port.max;
1034 if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
1046 on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1048 GstStructure *stats;
1049 GstRTSPMediaTrans *trans;
1051 GST_INFO ("%p: new source %p", stream, source);
1053 /* see if we have a stream to match with the origin of the RTCP packet */
1054 trans = g_object_get_qdata (source, ssrc_stream_map_key);
1055 if (trans == NULL) {
1056 g_object_get (source, "stats", &stats, NULL);
1058 const gchar *rtcp_from;
1060 dump_structure (stats);
1062 rtcp_from = gst_structure_get_string (stats, "rtcp-from");
1063 if ((trans = find_transport (stream, rtcp_from))) {
1064 GST_INFO ("%p: found transport %p for source %p", stream, trans,
1067 /* keep ref to the source */
1068 trans->rtpsource = source;
1070 g_object_set_qdata (source, ssrc_stream_map_key, trans);
1072 gst_structure_free (stats);
1075 GST_INFO ("%p: source %p for transport %p", stream, source, trans);
1080 on_ssrc_sdes (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1082 GST_INFO ("%p: new SDES %p", stream, source);
1086 on_ssrc_active (GObject * session, GObject * source,
1087 GstRTSPMediaStream * stream)
1089 GstRTSPMediaTrans *trans;
1091 trans = g_object_get_qdata (source, ssrc_stream_map_key);
1093 GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
1095 if (trans && trans->keep_alive)
1096 trans->keep_alive (trans->ka_user_data);
1100 GstStructure *stats;
1101 g_object_get (source, "stats", &stats, NULL);
1103 dump_structure (stats);
1104 gst_structure_free (stats);
1111 on_bye_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1113 GST_INFO ("%p: source %p bye", stream, source);
1117 on_bye_timeout (GObject * session, GObject * source,
1118 GstRTSPMediaStream * stream)
1120 GstRTSPMediaTrans *trans;
1122 GST_INFO ("%p: source %p bye timeout", stream, source);
1124 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
1125 trans->rtpsource = NULL;
1126 trans->timeout = TRUE;
1131 on_timeout (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1133 GstRTSPMediaTrans *trans;
1135 GST_INFO ("%p: source %p timeout", stream, source);
1137 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
1138 trans->rtpsource = NULL;
1139 trans->timeout = TRUE;
1143 static GstFlowReturn
1144 handle_new_buffer (GstAppSink * sink, gpointer user_data)
1148 GstRTSPMediaStream *stream;
1150 buffer = gst_app_sink_pull_buffer (sink);
1154 stream = (GstRTSPMediaStream *) user_data;
1156 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
1157 GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data;
1159 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
1161 tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data);
1164 tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data);
1167 gst_buffer_unref (buffer);
1172 static GstFlowReturn
1173 handle_new_buffer_list (GstAppSink * sink, gpointer user_data)
1176 GstBufferList *blist;
1177 GstRTSPMediaStream *stream;
1179 blist = gst_app_sink_pull_buffer_list (sink);
1183 stream = (GstRTSPMediaStream *) user_data;
1185 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
1186 GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data;
1188 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
1189 if (tr->send_rtp_list)
1190 tr->send_rtp_list (blist, tr->transport->interleaved.min,
1193 if (tr->send_rtcp_list)
1194 tr->send_rtcp_list (blist, tr->transport->interleaved.max,
1198 gst_buffer_list_unref (blist);
1203 static GstAppSinkCallbacks sink_cb = {
1204 NULL, /* not interested in EOS */
1205 NULL, /* not interested in preroll buffers */
1207 handle_new_buffer_list
1210 /* prepare the pipeline objects to handle @stream in @media */
1212 setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
1215 GstPad *pad, *teepad, *selpad;
1216 GstPadLinkReturn ret;
1219 /* allocate udp ports, we will have 4 of them, 2 for receiving RTP/RTCP and 2
1220 * for sending RTP/RTCP. The sender and receiver ports are shared between the
1222 if (!alloc_udp_ports (media, stream))
1225 /* add the ports to the pipeline */
1226 for (i = 0; i < 2; i++) {
1227 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsink[i]);
1228 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->udpsrc[i]);
1231 /* create elements for the TCP transfer */
1232 for (i = 0; i < 2; i++) {
1233 stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
1234 stream->appsink[i] = gst_element_factory_make ("appsink", NULL);
1235 g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL);
1236 g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL);
1237 g_object_set (stream->appsink[i], "preroll-queue-len", 1, NULL);
1238 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]);
1239 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]);
1240 gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
1241 &sink_cb, stream, NULL);
1244 /* hook up the stream to the RTP session elements. */
1245 name = g_strdup_printf ("send_rtp_sink_%d", idx);
1246 stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
1248 name = g_strdup_printf ("send_rtp_src_%d", idx);
1249 stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name);
1251 name = g_strdup_printf ("send_rtcp_src_%d", idx);
1252 stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name);
1254 name = g_strdup_printf ("recv_rtcp_sink_%d", idx);
1255 stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name);
1257 name = g_strdup_printf ("recv_rtp_sink_%d", idx);
1258 stream->recv_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
1261 /* get the session */
1262 g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx,
1265 g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
1267 g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
1269 g_signal_connect (stream->session, "on-ssrc-active",
1270 (GCallback) on_ssrc_active, stream);
1271 g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
1273 g_signal_connect (stream->session, "on-bye-timeout",
1274 (GCallback) on_bye_timeout, stream);
1275 g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
1278 /* link the RTP pad to the session manager */
1279 ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
1280 if (ret != GST_PAD_LINK_OK)
1283 /* make tee for RTP and link to stream */
1284 stream->tee[0] = gst_element_factory_make ("tee", NULL);
1285 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[0]);
1287 pad = gst_element_get_static_pad (stream->tee[0], "sink");
1288 gst_pad_link (stream->send_rtp_src, pad);
1289 gst_object_unref (pad);
1291 /* link RTP sink, we're pretty sure this will work. */
1292 teepad = gst_element_get_request_pad (stream->tee[0], "src%d");
1293 pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
1294 gst_pad_link (teepad, pad);
1295 gst_object_unref (pad);
1296 gst_object_unref (teepad);
1298 teepad = gst_element_get_request_pad (stream->tee[0], "src%d");
1299 pad = gst_element_get_static_pad (stream->appsink[0], "sink");
1300 gst_pad_link (teepad, pad);
1301 gst_object_unref (pad);
1302 gst_object_unref (teepad);
1304 /* make tee for RTCP */
1305 stream->tee[1] = gst_element_factory_make ("tee", NULL);
1306 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]);
1308 pad = gst_element_get_static_pad (stream->tee[1], "sink");
1309 gst_pad_link (stream->send_rtcp_src, pad);
1310 gst_object_unref (pad);
1312 /* link RTCP elements */
1313 teepad = gst_element_get_request_pad (stream->tee[1], "src%d");
1314 pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
1315 gst_pad_link (teepad, pad);
1316 gst_object_unref (pad);
1317 gst_object_unref (teepad);
1319 teepad = gst_element_get_request_pad (stream->tee[1], "src%d");
1320 pad = gst_element_get_static_pad (stream->appsink[1], "sink");
1321 gst_pad_link (teepad, pad);
1322 gst_object_unref (pad);
1323 gst_object_unref (teepad);
1325 /* make selector for the RTP receivers */
1326 stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL);
1327 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
1329 pad = gst_element_get_static_pad (stream->selector[0], "src");
1330 gst_pad_link (pad, stream->recv_rtp_sink);
1331 gst_object_unref (pad);
1333 selpad = gst_element_get_request_pad (stream->selector[0], "sink%d");
1334 pad = gst_element_get_static_pad (stream->udpsrc[0], "src");
1335 gst_pad_link (pad, selpad);
1336 gst_object_unref (pad);
1337 gst_object_unref (selpad);
1339 selpad = gst_element_get_request_pad (stream->selector[0], "sink%d");
1340 pad = gst_element_get_static_pad (stream->appsrc[0], "src");
1341 gst_pad_link (pad, selpad);
1342 gst_object_unref (pad);
1343 gst_object_unref (selpad);
1345 /* make selector for the RTCP receivers */
1346 stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL);
1347 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
1349 pad = gst_element_get_static_pad (stream->selector[1], "src");
1350 gst_pad_link (pad, stream->recv_rtcp_sink);
1351 gst_object_unref (pad);
1353 selpad = gst_element_get_request_pad (stream->selector[1], "sink%d");
1354 pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
1355 gst_pad_link (pad, selpad);
1356 gst_object_unref (pad);
1357 gst_object_unref (selpad);
1359 selpad = gst_element_get_request_pad (stream->selector[1], "sink%d");
1360 pad = gst_element_get_static_pad (stream->appsrc[1], "src");
1361 gst_pad_link (pad, selpad);
1362 gst_object_unref (pad);
1363 gst_object_unref (selpad);
1365 /* we set and keep these to playing so that they don't cause NO_PREROLL return
1367 gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING);
1368 gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING);
1369 gst_element_set_locked_state (stream->udpsrc[0], TRUE);
1370 gst_element_set_locked_state (stream->udpsrc[1], TRUE);
1372 /* be notified of caps changes */
1373 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
1374 (GCallback) caps_notify, stream);
1376 stream->prepared = TRUE;
1383 GST_WARNING ("failed to link stream %d", idx);
1389 unlock_streams (GstRTSPMedia * media)
1393 /* unlock the udp src elements */
1394 n_streams = gst_rtsp_media_n_streams (media);
1395 for (i = 0; i < n_streams; i++) {
1396 GstRTSPMediaStream *stream;
1398 stream = gst_rtsp_media_get_stream (media, i);
1400 gst_element_set_locked_state (stream->udpsrc[0], FALSE);
1401 gst_element_set_locked_state (stream->udpsrc[1], FALSE);
1406 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1408 g_mutex_lock (media->lock);
1409 /* never overwrite the error status */
1410 if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
1411 media->status = status;
1412 GST_DEBUG ("setting new status to %d", status);
1413 g_cond_broadcast (media->cond);
1414 g_mutex_unlock (media->lock);
1417 static GstRTSPMediaStatus
1418 gst_rtsp_media_get_status (GstRTSPMedia * media)
1420 GstRTSPMediaStatus result;
1423 g_mutex_lock (media->lock);
1424 g_get_current_time (&timeout);
1425 g_time_val_add (&timeout, 20 * G_USEC_PER_SEC);
1426 /* while we are preparing, wait */
1427 while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1428 GST_DEBUG ("waiting for status change");
1429 if (!g_cond_timed_wait (media->cond, media->lock, &timeout)) {
1430 GST_DEBUG ("timeout, assuming error status");
1431 media->status = GST_RTSP_MEDIA_STATUS_ERROR;
1434 /* could be success or error */
1435 result = media->status;
1436 GST_DEBUG ("got status %d", result);
1437 g_mutex_unlock (media->lock);
1443 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1445 GstMessageType type;
1447 type = GST_MESSAGE_TYPE (message);
1450 case GST_MESSAGE_STATE_CHANGED:
1452 case GST_MESSAGE_BUFFERING:
1456 gst_message_parse_buffering (message, &percent);
1458 /* no state management needed for live pipelines */
1462 if (percent == 100) {
1463 /* a 100% message means buffering is done */
1464 media->buffering = FALSE;
1465 /* if the desired state is playing, go back */
1466 if (media->target_state == GST_STATE_PLAYING) {
1467 GST_INFO ("Buffering done, setting pipeline to PLAYING");
1468 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1470 GST_INFO ("Buffering done");
1473 /* buffering busy */
1474 if (media->buffering == FALSE) {
1475 if (media->target_state == GST_STATE_PLAYING) {
1476 /* we were not buffering but PLAYING, PAUSE the pipeline. */
1477 GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1478 gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1480 GST_INFO ("Buffering ...");
1483 media->buffering = TRUE;
1487 case GST_MESSAGE_LATENCY:
1489 gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
1492 case GST_MESSAGE_ERROR:
1497 gst_message_parse_error (message, &gerror, &debug);
1498 GST_WARNING ("%p: got error %s (%s)", media, gerror->message, debug);
1499 g_error_free (gerror);
1502 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1505 case GST_MESSAGE_WARNING:
1510 gst_message_parse_warning (message, &gerror, &debug);
1511 GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1512 g_error_free (gerror);
1516 case GST_MESSAGE_ELEMENT:
1518 case GST_MESSAGE_STREAM_STATUS:
1520 case GST_MESSAGE_ASYNC_DONE:
1521 if (!media->adding) {
1522 /* when we are dynamically adding pads, the addition of the udpsrc will
1523 * temporarily produce ASYNC_DONE messages. We have to ignore them and
1524 * wait for the final ASYNC_DONE after everything prerolled */
1525 GST_INFO ("%p: got ASYNC_DONE", media);
1526 collect_media_stats (media);
1528 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1530 GST_INFO ("%p: ignoring ASYNC_DONE", media);
1533 case GST_MESSAGE_EOS:
1534 GST_INFO ("%p: got EOS", media);
1535 if (media->eos_pending) {
1536 GST_DEBUG ("shutting down after EOS");
1537 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1538 media->eos_pending = FALSE;
1539 g_object_unref (media);
1543 GST_INFO ("%p: got message type %s", media,
1544 gst_message_type_get_name (type));
1551 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1553 GstRTSPMediaClass *klass;
1556 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1558 if (klass->handle_message)
1559 ret = klass->handle_message (media, message);
1566 /* called from streaming threads */
1568 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1570 GstRTSPMediaStream *stream;
1574 i = media->streams->len + 1;
1576 GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i);
1578 stream = g_new0 (GstRTSPMediaStream, 1);
1579 stream->payloader = element;
1581 name = g_strdup_printf ("dynpay%d", i);
1583 media->adding = TRUE;
1585 /* ghost the pad of the payloader to the element */
1586 stream->srcpad = gst_ghost_pad_new (name, pad);
1587 gst_pad_set_active (stream->srcpad, TRUE);
1588 gst_element_add_pad (media->element, stream->srcpad);
1591 /* add stream now */
1592 g_array_append_val (media->streams, stream);
1594 setup_stream (stream, i, media);
1596 for (i = 0; i < 2; i++) {
1597 gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED);
1598 gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED);
1599 gst_element_set_state (stream->tee[i], GST_STATE_PAUSED);
1600 gst_element_set_state (stream->selector[i], GST_STATE_PAUSED);
1601 gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED);
1603 media->adding = FALSE;
1607 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1609 GST_INFO ("no more pads");
1610 if (media->fakesink) {
1611 gst_object_ref (media->fakesink);
1612 gst_bin_remove (GST_BIN (media->pipeline), media->fakesink);
1613 gst_element_set_state (media->fakesink, GST_STATE_NULL);
1614 gst_object_unref (media->fakesink);
1615 media->fakesink = NULL;
1616 GST_INFO ("removed fakesink");
1621 * gst_rtsp_media_prepare:
1622 * @media: a #GstRTSPMedia
1624 * Prepare @media for streaming. This function will create the pipeline and
1625 * other objects to manage the streaming.
1627 * It will preroll the pipeline and collect vital information about the streams
1628 * such as the duration.
1630 * Returns: %TRUE on success.
1633 gst_rtsp_media_prepare (GstRTSPMedia * media)
1635 GstStateChangeReturn ret;
1636 GstRTSPMediaStatus status;
1638 GstRTSPMediaClass *klass;
1642 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1645 if (!media->reusable && media->reused)
1648 GST_INFO ("preparing media %p", media);
1650 /* reset some variables */
1651 media->is_live = FALSE;
1652 media->buffering = FALSE;
1653 /* we're preparing now */
1654 media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1656 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
1658 /* add the pipeline bus to our custom mainloop */
1659 media->source = gst_bus_create_watch (bus);
1660 gst_object_unref (bus);
1662 g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL);
1664 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1665 media->id = g_source_attach (media->source, klass->context);
1667 media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL);
1669 /* add stuff to the bin */
1670 gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
1672 /* link streams we already have, other streams might appear when we have
1673 * dynamic elements */
1674 n_streams = gst_rtsp_media_n_streams (media);
1675 for (i = 0; i < n_streams; i++) {
1676 GstRTSPMediaStream *stream;
1678 stream = gst_rtsp_media_get_stream (media, i);
1680 setup_stream (stream, i, media);
1683 for (walk = media->dynamic; walk; walk = g_list_next (walk)) {
1684 GstElement *elem = walk->data;
1686 GST_INFO ("adding callbacks for dynamic element %p", elem);
1688 g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1689 g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1691 /* we add a fakesink here in order to make the state change async. We remove
1692 * the fakesink again in the no-more-pads callback. */
1693 media->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1694 gst_bin_add (GST_BIN (media->pipeline), media->fakesink);
1697 GST_INFO ("setting pipeline to PAUSED for media %p", media);
1698 /* first go to PAUSED */
1699 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1700 media->target_state = GST_STATE_PAUSED;
1703 case GST_STATE_CHANGE_SUCCESS:
1704 GST_INFO ("SUCCESS state change for media %p", media);
1706 case GST_STATE_CHANGE_ASYNC:
1707 GST_INFO ("ASYNC state change for media %p", media);
1709 case GST_STATE_CHANGE_NO_PREROLL:
1710 /* we need to go to PLAYING */
1711 GST_INFO ("NO_PREROLL state change: live media %p", media);
1712 media->is_live = TRUE;
1713 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1714 if (ret == GST_STATE_CHANGE_FAILURE)
1717 case GST_STATE_CHANGE_FAILURE:
1721 /* now wait for all pads to be prerolled */
1722 status = gst_rtsp_media_get_status (media);
1723 if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1726 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1728 GST_INFO ("object %p is prerolled", media);
1740 GST_WARNING ("can not reuse media %p", media);
1745 GST_WARNING ("failed to preroll pipeline");
1746 unlock_streams (media);
1747 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1748 gst_rtsp_media_unprepare (media);
1754 * gst_rtsp_media_unprepare:
1755 * @media: a #GstRTSPMedia
1757 * Unprepare @media. After this call, the media should be prepared again before
1758 * it can be used again. If the media is set to be non-reusable, a new instance
1761 * Returns: %TRUE on success.
1764 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1766 GstRTSPMediaClass *klass;
1769 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1772 GST_INFO ("unprepare media %p", media);
1773 media->target_state = GST_STATE_NULL;
1775 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1776 if (klass->unprepare)
1777 success = klass->unprepare (media);
1781 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1782 media->reused = TRUE;
1784 /* when the media is not reusable, this will effectively unref the media and
1786 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1792 default_unprepare (GstRTSPMedia * media)
1794 if (media->eos_shutdown) {
1795 GST_DEBUG ("sending EOS for shutdown");
1796 /* ref so that we don't disappear */
1797 g_object_ref (media);
1798 media->eos_pending = TRUE;
1799 gst_element_send_event (media->pipeline, gst_event_new_eos ());
1800 /* we need to go to playing again for the EOS to propagate, normally in this
1801 * state, nothing is receiving data from us anymore so this is ok. */
1802 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1804 GST_DEBUG ("shutting down");
1805 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1811 add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
1812 gchar * dest, gint min, gint max)
1814 gboolean do_add = TRUE;
1815 RTSPDestination *ndest;
1817 if (stream->filter_duplicates) {
1818 RTSPDestination fdest;
1825 /* first see if we already added this destination */
1827 g_list_find_custom (stream->destinations, &fdest,
1828 (GCompareFunc) dest_compare);
1830 ndest = (RTSPDestination *) find->data;
1832 GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max,
1840 GST_INFO ("adding %s:%d-%d", dest, min, max);
1841 g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
1842 g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
1844 if (stream->filter_duplicates) {
1845 ndest = create_destination (dest, min, max);
1846 stream->destinations = g_list_prepend (stream->destinations, ndest);
1852 remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
1853 gchar * dest, gint min, gint max)
1855 gboolean do_remove = TRUE;
1856 RTSPDestination *ndest = NULL;
1859 if (stream->filter_duplicates) {
1860 RTSPDestination fdest;
1866 /* first see if we already added this destination */
1868 g_list_find_custom (stream->destinations, &fdest,
1869 (GCompareFunc) dest_compare);
1873 ndest = (RTSPDestination *) find->data;
1874 if (--ndest->count > 0) {
1876 GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max,
1882 GST_INFO ("removing %s:%d-%d", dest, min, max);
1883 g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
1884 g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
1886 if (stream->filter_duplicates) {
1887 stream->destinations = g_list_delete_link (stream->destinations, find);
1888 free_destination (ndest);
1894 * gst_rtsp_media_set_state:
1895 * @media: a #GstRTSPMedia
1896 * @state: the target state of the media
1897 * @transports: a #GArray of #GstRTSPMediaTrans pointers
1899 * Set the state of @media to @state and for the transports in @transports.
1901 * Returns: %TRUE on success.
1904 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1905 GArray * transports)
1908 GstStateChangeReturn ret;
1909 gboolean add, remove, do_state;
1912 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1913 g_return_val_if_fail (transports != NULL, FALSE);
1915 /* NULL and READY are the same */
1916 if (state == GST_STATE_READY)
1917 state = GST_STATE_NULL;
1919 add = remove = FALSE;
1921 GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1925 case GST_STATE_NULL:
1926 /* unlock the streams so that they follow the state changes from now on */
1927 unlock_streams (media);
1929 case GST_STATE_PAUSED:
1930 /* we're going from PLAYING to PAUSED, READY or NULL, remove */
1931 if (media->target_state == GST_STATE_PLAYING)
1934 case GST_STATE_PLAYING:
1935 /* we're going to PLAYING, add */
1941 old_active = media->active;
1943 for (i = 0; i < transports->len; i++) {
1944 GstRTSPMediaTrans *tr;
1945 GstRTSPMediaStream *stream;
1946 GstRTSPTransport *trans;
1948 /* we need a non-NULL entry in the array */
1949 tr = g_array_index (transports, GstRTSPMediaTrans *, i);
1953 /* we need a transport */
1954 if (!(trans = tr->transport))
1957 /* get the stream and add the destinations */
1958 stream = gst_rtsp_media_get_stream (media, tr->idx);
1959 switch (trans->lower_transport) {
1960 case GST_RTSP_LOWER_TRANS_UDP:
1961 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1966 dest = trans->destination;
1967 if (trans->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1968 min = trans->port.min;
1969 max = trans->port.max;
1971 min = trans->client_port.min;
1972 max = trans->client_port.max;
1975 if (add && !tr->active) {
1976 add_udp_destination (media, stream, dest, min, max);
1977 stream->transports = g_list_prepend (stream->transports, tr);
1980 } else if (remove && tr->active) {
1981 remove_udp_destination (media, stream, dest, min, max);
1982 stream->transports = g_list_remove (stream->transports, tr);
1988 case GST_RTSP_LOWER_TRANS_TCP:
1989 if (add && !tr->active) {
1990 GST_INFO ("adding TCP %s", trans->destination);
1991 stream->transports = g_list_prepend (stream->transports, tr);
1994 } else if (remove && tr->active) {
1995 GST_INFO ("removing TCP %s", trans->destination);
1996 stream->transports = g_list_remove (stream->transports, tr);
2002 GST_INFO ("Unknown transport %d", trans->lower_transport);
2007 /* we just added the first media, do the playing state change */
2008 if (old_active == 0 && add)
2010 /* if we have no more active media, do the downward state changes */
2011 else if (media->active == 0)
2016 GST_INFO ("state %d active %d media %p do_state %d", state, media->active,
2019 if (media->target_state != state) {
2021 if (state == GST_STATE_NULL) {
2022 gst_rtsp_media_unprepare (media);
2024 GST_INFO ("state %s media %p", gst_element_state_get_name (state),
2026 media->target_state = state;
2027 ret = gst_element_set_state (media->pipeline, state);
2030 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
2034 /* remember where we are */
2035 if (state == GST_STATE_PAUSED || old_active != media->active)
2036 collect_media_stats (media);
2042 * gst_rtsp_media_remove_elements:
2043 * @media: a #GstRTSPMedia
2045 * Remove all elements and the pipeline controlled by @media.
2048 gst_rtsp_media_remove_elements (GstRTSPMedia * media)
2052 unlock_streams (media);
2054 for (i = 0; i < media->streams->len; i++) {
2055 GstRTSPMediaStream *stream;
2057 GST_INFO ("Removing elements of stream %d from pipeline", i);
2059 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
2061 gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
2063 g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
2065 for (j = 0; j < 2; j++) {
2066 gst_element_set_state (stream->udpsrc[j], GST_STATE_NULL);
2067 gst_element_set_state (stream->udpsink[j], GST_STATE_NULL);
2068 gst_element_set_state (stream->appsrc[j], GST_STATE_NULL);
2069 gst_element_set_state (stream->appsink[j], GST_STATE_NULL);
2070 gst_element_set_state (stream->tee[j], GST_STATE_NULL);
2071 gst_element_set_state (stream->selector[j], GST_STATE_NULL);
2073 gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[j]);
2074 gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]);
2075 gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]);
2076 gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[j]);
2077 gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]);
2078 gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]);
2081 gst_caps_unref (stream->caps);
2082 stream->caps = NULL;
2083 gst_rtsp_media_stream_free (stream);
2085 g_array_remove_range (media->streams, 0, media->streams->len);
2087 gst_element_set_state (media->rtpbin, GST_STATE_NULL);
2088 gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin);
2090 gst_object_unref (media->pipeline);
2091 media->pipeline = NULL;