2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 * * Modifications by Samsung Electronics Co., Ltd.
24 * 1. Applied Miracast WFD Server function
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
34 #include <gst/app/gstappsrc.h>
35 #include <gst/app/gstappsink.h>
37 #include "rtsp-funnel.h"
38 #include "rtsp-media.h"
40 #define DEFAULT_SHARED FALSE
41 #define DEFAULT_REUSABLE FALSE
42 #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
43 //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
44 #define DEFAULT_EOS_SHUTDOWN FALSE
46 /* define to dump received RTCP packets */
67 GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
68 #define GST_CAT_DEFAULT rtsp_media_debug
70 static GQuark ssrc_stream_map_key;
72 static void gst_rtsp_media_get_property (GObject * object, guint propid,
73 GValue * value, GParamSpec * pspec);
74 static void gst_rtsp_media_set_property (GObject * object, guint propid,
75 const GValue * value, GParamSpec * pspec);
76 static void gst_rtsp_media_finalize (GObject * obj);
78 static gpointer do_loop (GstRTSPMediaClass * klass);
79 static gboolean default_handle_message (GstRTSPMedia * media,
80 GstMessage * message);
81 static gboolean default_unprepare (GstRTSPMedia * media);
82 static void unlock_streams (GstRTSPMedia * media);
84 static guint gst_rtsp_media_signals[SIGNAL_LAST] = { 0 };
86 G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
89 gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
91 GObjectClass *gobject_class;
94 gobject_class = G_OBJECT_CLASS (klass);
96 gobject_class->get_property = gst_rtsp_media_get_property;
97 gobject_class->set_property = gst_rtsp_media_set_property;
98 gobject_class->finalize = gst_rtsp_media_finalize;
100 g_object_class_install_property (gobject_class, PROP_SHARED,
101 g_param_spec_boolean ("shared", "Shared",
102 "If this media pipeline can be shared", DEFAULT_SHARED,
103 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
105 g_object_class_install_property (gobject_class, PROP_REUSABLE,
106 g_param_spec_boolean ("reusable", "Reusable",
107 "If this media pipeline can be reused after an unprepare",
108 DEFAULT_REUSABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
110 g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
111 g_param_spec_flags ("protocols", "Protocols",
112 "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
113 DEFAULT_PROTOCOLS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
115 g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
116 g_param_spec_boolean ("eos-shutdown", "EOS Shutdown",
117 "Send an EOS event to the pipeline before unpreparing",
118 DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
120 gst_rtsp_media_signals[SIGNAL_PREPARED] =
121 g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
122 G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
123 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
125 gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
126 g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
127 G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
128 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
130 gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
131 g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
132 G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
133 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
135 klass->context = g_main_context_new ();
136 klass->loop = g_main_loop_new (klass->context, TRUE);
138 GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
140 klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
142 g_critical ("could not start bus thread: %s", error->message);
144 klass->handle_message = default_handle_message;
145 klass->unprepare = default_unprepare;
147 ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
149 gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL);
154 gst_rtsp_media_init (GstRTSPMedia * media)
156 media->streams = g_array_new (FALSE, TRUE, sizeof (GstRTSPMediaStream *));
157 media->lock = g_mutex_new ();
158 media->cond = g_cond_new ();
160 media->shared = DEFAULT_SHARED;
161 media->reusable = DEFAULT_REUSABLE;
162 media->protocols = DEFAULT_PROTOCOLS;
163 media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
166 /* FIXME. this should be done in multiudpsink */
175 dest_compare (RTSPDestination * a, RTSPDestination * b)
177 if ((a->min == b->min) && (a->max == b->max)
178 && (strcmp (a->dest, b->dest) == 0))
184 static RTSPDestination *
185 create_destination (const gchar * dest, gint min, gint max)
187 RTSPDestination *res;
189 res = g_slice_new (RTSPDestination);
191 res->dest = g_strdup (dest);
199 free_destination (RTSPDestination * dest)
202 g_slice_free (RTSPDestination, dest);
206 gst_rtsp_media_trans_cleanup (GstRTSPMediaTrans * trans)
208 if (trans->transport) {
209 gst_rtsp_transport_free (trans->transport);
210 trans->transport = NULL;
212 if (trans->rtpsource) {
213 g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL);
214 trans->rtpsource = NULL;
219 gst_rtsp_media_stream_free (GstRTSPMediaStream * stream)
222 g_object_unref (stream->session);
225 gst_caps_unref (stream->caps);
227 if (stream->send_rtp_sink)
228 gst_object_unref (stream->send_rtp_sink);
229 if (stream->send_rtp_src)
230 gst_object_unref (stream->send_rtp_src);
231 if (stream->send_rtcp_src)
232 gst_object_unref (stream->send_rtcp_src);
233 if (stream->recv_rtcp_sink)
234 gst_object_unref (stream->recv_rtcp_sink);
235 if (stream->recv_rtp_sink)
236 gst_object_unref (stream->recv_rtp_sink);
238 g_list_free (stream->transports);
240 g_list_foreach (stream->destinations, (GFunc) free_destination, NULL);
241 g_list_free (stream->destinations);
247 gst_rtsp_media_finalize (GObject * obj)
252 media = GST_RTSP_MEDIA (obj);
254 GST_INFO ("finalize media %p", media);
256 if (media->pipeline) {
257 unlock_streams (media);
258 gst_element_set_state (media->pipeline, GST_STATE_NULL);
259 gst_object_unref (media->pipeline);
262 for (i = 0; i < media->streams->len; i++) {
263 GstRTSPMediaStream *stream;
265 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
267 gst_rtsp_media_stream_free (stream);
269 g_array_free (media->streams, TRUE);
271 g_list_foreach (media->dynamic, (GFunc) gst_object_unref, NULL);
272 g_list_free (media->dynamic);
275 g_source_destroy (media->source);
276 g_source_unref (media->source);
278 g_mutex_free (media->lock);
279 g_cond_free (media->cond);
281 G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
285 gst_rtsp_media_get_property (GObject * object, guint propid,
286 GValue * value, GParamSpec * pspec)
288 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
292 g_value_set_boolean (value, gst_rtsp_media_is_shared (media));
295 g_value_set_boolean (value, gst_rtsp_media_is_reusable (media));
298 g_value_set_flags (value, gst_rtsp_media_get_protocols (media));
300 case PROP_EOS_SHUTDOWN:
301 g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
309 gst_rtsp_media_set_property (GObject * object, guint propid,
310 const GValue * value, GParamSpec * pspec)
312 GstRTSPMedia *media = GST_RTSP_MEDIA (object);
316 gst_rtsp_media_set_shared (media, g_value_get_boolean (value));
319 gst_rtsp_media_set_reusable (media, g_value_get_boolean (value));
322 gst_rtsp_media_set_protocols (media, g_value_get_flags (value));
324 case PROP_EOS_SHUTDOWN:
325 gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
328 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
333 do_loop (GstRTSPMediaClass * klass)
335 GST_INFO ("enter mainloop");
336 g_main_loop_run (klass->loop);
337 GST_INFO ("exit mainloop");
343 collect_media_stats (GstRTSPMedia * media)
346 gint64 position, duration;
348 media->range.unit = GST_RTSP_RANGE_NPT;
350 if (media->is_live) {
351 media->range.min.type = GST_RTSP_TIME_NOW;
352 media->range.min.seconds = -1;
353 media->range.max.type = GST_RTSP_TIME_END;
354 media->range.max.seconds = -1;
356 /* get the position */
357 format = GST_FORMAT_TIME;
358 if (!gst_element_query_position (media->pipeline, format, &position)) {
359 GST_INFO ("position query failed");
363 /* get the duration */
364 format = GST_FORMAT_TIME;
365 if (!gst_element_query_duration (media->pipeline, format, &duration)) {
366 GST_INFO ("duration query failed");
370 GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
371 GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
373 if (position == -1) {
374 media->range.min.type = GST_RTSP_TIME_NOW;
375 media->range.min.seconds = -1;
377 media->range.min.type = GST_RTSP_TIME_SECONDS;
378 media->range.min.seconds = ((gdouble) position) / GST_SECOND;
380 if (duration == -1) {
381 media->range.max.type = GST_RTSP_TIME_END;
382 media->range.max.seconds = -1;
384 media->range.max.type = GST_RTSP_TIME_SECONDS;
385 media->range.max.seconds = ((gdouble) duration) / GST_SECOND;
391 * gst_rtsp_media_new:
393 * Create a new #GstRTSPMedia instance. The #GstRTSPMedia object contains the
394 * element to produde RTP data for one or more related (audio/video/..)
397 * Returns: a new #GstRTSPMedia object.
400 gst_rtsp_media_new (void)
402 GstRTSPMedia *result;
404 result = g_object_new (GST_TYPE_RTSP_MEDIA, NULL);
410 * gst_rtsp_media_set_shared:
411 * @media: a #GstRTSPMedia
412 * @shared: the new value
414 * Set or unset if the pipeline for @media can be shared will multiple clients.
415 * When @shared is %TRUE, client requests for this media will share the media
419 gst_rtsp_media_set_shared (GstRTSPMedia * media, gboolean shared)
421 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
423 media->shared = shared;
427 * gst_rtsp_media_is_shared:
428 * @media: a #GstRTSPMedia
430 * Check if the pipeline for @media can be shared between multiple clients.
432 * Returns: %TRUE if the media can be shared between clients.
435 gst_rtsp_media_is_shared (GstRTSPMedia * media)
437 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
439 return media->shared;
443 * gst_rtsp_media_set_reusable:
444 * @media: a #GstRTSPMedia
445 * @reusable: the new value
447 * Set or unset if the pipeline for @media can be reused after the pipeline has
451 gst_rtsp_media_set_reusable (GstRTSPMedia * media, gboolean reusable)
453 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
455 media->reusable = reusable;
459 * gst_rtsp_media_is_reusable:
460 * @media: a #GstRTSPMedia
462 * Check if the pipeline for @media can be reused after an unprepare.
464 * Returns: %TRUE if the media can be reused
467 gst_rtsp_media_is_reusable (GstRTSPMedia * media)
469 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
471 return media->reusable;
475 * gst_rtsp_media_set_protocols:
476 * @media: a #GstRTSPMedia
477 * @protocols: the new flags
479 * Configure the allowed lower transport for @media.
482 gst_rtsp_media_set_protocols (GstRTSPMedia * media, GstRTSPLowerTrans protocols)
484 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
486 media->protocols = protocols;
490 * gst_rtsp_media_get_protocols:
491 * @media: a #GstRTSPMedia
493 * Get the allowed protocols of @media.
495 * Returns: a #GstRTSPLowerTrans
498 gst_rtsp_media_get_protocols (GstRTSPMedia * media)
500 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media),
501 GST_RTSP_LOWER_TRANS_UNKNOWN);
503 return media->protocols;
507 * gst_rtsp_media_set_eos_shutdown:
508 * @media: a #GstRTSPMedia
509 * @eos_shutdown: the new value
511 * Set or unset if an EOS event will be sent to the pipeline for @media before
515 gst_rtsp_media_set_eos_shutdown (GstRTSPMedia * media, gboolean eos_shutdown)
517 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
519 media->eos_shutdown = eos_shutdown;
523 * gst_rtsp_media_is_eos_shutdown:
524 * @media: a #GstRTSPMedia
526 * Check if the pipeline for @media will send an EOS down the pipeline before
529 * Returns: %TRUE if the media will send EOS before unpreparing.
532 gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
534 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
536 return media->eos_shutdown;
540 * gst_rtsp_media_set_auth:
541 * @media: a #GstRTSPMedia
542 * @auth: a #GstRTSPAuth
544 * configure @auth to be used as the authentication manager of @media.
547 gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
551 g_return_if_fail (GST_IS_RTSP_MEDIA (media));
560 g_object_unref (old);
565 * gst_rtsp_media_get_auth:
566 * @media: a #GstRTSPMedia
568 * Get the #GstRTSPAuth used as the authentication manager of @media.
570 * Returns: the #GstRTSPAuth of @media. g_object_unref() after
574 gst_rtsp_media_get_auth (GstRTSPMedia * media)
578 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
580 if ((result = media->auth))
581 g_object_ref (result);
588 * gst_rtsp_media_n_streams:
589 * @media: a #GstRTSPMedia
591 * Get the number of streams in this media.
593 * Returns: The number of streams.
596 gst_rtsp_media_n_streams (GstRTSPMedia * media)
598 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0);
600 return media->streams->len;
604 * gst_rtsp_media_get_stream:
605 * @media: a #GstRTSPMedia
606 * @idx: the stream index
608 * Retrieve the stream with index @idx from @media.
610 * Returns: the #GstRTSPMediaStream at index @idx or %NULL when a stream with
611 * that index did not exist.
614 gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
616 GstRTSPMediaStream *res;
618 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
620 if (idx < media->streams->len)
621 res = g_array_index (media->streams, GstRTSPMediaStream *, idx);
629 * gst_rtsp_media_get_range_string:
630 * @media: a #GstRTSPMedia
631 * @play: for the PLAY request
633 * Get the current range as a string.
635 * Returns: The range as a string, g_free() after usage.
638 gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
641 GstRTSPTimeRange range;
644 range = media->range;
646 if (!play && media->active > 0) {
647 range.min.type = GST_RTSP_TIME_NOW;
648 range.min.seconds = -1;
651 result = gst_rtsp_range_to_string (&range);
657 * gst_rtsp_media_seek:
658 * @media: a #GstRTSPMedia
659 * @range: a #GstRTSPTimeRange
661 * Seek the pipeline to @range.
663 * Returns: %TRUE on success.
666 gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
671 GstSeekType start_type, stop_type;
673 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
674 g_return_val_if_fail (range != NULL, FALSE);
676 if (range->unit != GST_RTSP_RANGE_NPT)
679 /* depends on the current playing state of the pipeline. We might need to
680 * queue this until we get EOS. */
681 flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT;
683 start_type = stop_type = GST_SEEK_TYPE_NONE;
685 switch (range->min.type) {
686 case GST_RTSP_TIME_NOW:
689 case GST_RTSP_TIME_SECONDS:
690 /* only seek when something changed */
691 if (media->range.min.seconds == range->min.seconds) {
694 start = range->min.seconds * GST_SECOND;
695 start_type = GST_SEEK_TYPE_SET;
698 case GST_RTSP_TIME_END:
702 switch (range->max.type) {
703 case GST_RTSP_TIME_SECONDS:
704 /* only seek when something changed */
705 if (media->range.max.seconds == range->max.seconds) {
708 stop = range->max.seconds * GST_SECOND;
709 stop_type = GST_SEEK_TYPE_SET;
712 case GST_RTSP_TIME_END:
714 stop_type = GST_SEEK_TYPE_SET;
716 case GST_RTSP_TIME_NOW:
721 if (start != -1 || stop != -1) {
722 GST_INFO ("seeking to %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
723 GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
725 res = gst_element_seek (media->pipeline, 1.0, GST_FORMAT_TIME,
726 flags, start_type, start, stop_type, stop);
728 /* and block for the seek to complete */
729 GST_INFO ("done seeking %d", res);
730 gst_element_get_state (media->pipeline, NULL, NULL, -1);
731 GST_INFO ("prerolled again");
733 collect_media_stats (media);
735 GST_INFO ("no seek needed");
744 GST_WARNING ("seek unit %d not supported", range->unit);
749 GST_WARNING ("weird range type %d not supported", range->min.type);
755 * gst_rtsp_media_stream_rtp:
756 * @stream: a #GstRTSPMediaStream
757 * @buffer: a #GstBuffer
759 * Handle an RTP buffer for the stream. This method is usually called when a
760 * message has been received from a client using the TCP transport.
762 * This function takes ownership of @buffer.
764 * Returns: a GstFlowReturn.
767 gst_rtsp_media_stream_rtp (GstRTSPMediaStream * stream, GstBuffer * buffer)
771 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer);
777 * gst_rtsp_media_stream_rtcp:
778 * @stream: a #GstRTSPMediaStream
779 * @buffer: a #GstBuffer
781 * Handle an RTCP buffer for the stream. This method is usually called when a
782 * message has been received from a client using the TCP transport.
784 * This function takes ownership of @buffer.
786 * Returns: a GstFlowReturn.
789 gst_rtsp_media_stream_rtcp (GstRTSPMediaStream * stream, GstBuffer * buffer)
793 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer);
798 /* Allocate the udp ports and sockets */
800 alloc_udp_ports (GstRTSPMedia * media, GstRTSPMediaStream * stream)
802 GstStateChangeReturn ret;
803 GstElement *udpsrc0, *udpsrc1;
804 GstElement *udpsink0, *udpsink1;
805 gint tmp_rtp, tmp_rtcp;
807 gint rtpport, rtcpport, sockfd;
816 /* Start with random port */
817 #if 0 //Changes for testing with dongle
823 host = "udp://[::0]";
825 host = "udp://0.0.0.0";
827 /* try to allocate 2 UDP ports, the RTP port should be an even
828 * number and the RTCP port should be the next (uneven) port */
830 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
832 goto no_udp_protocol;
833 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
835 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
836 if (ret == GST_STATE_CHANGE_FAILURE) {
842 gst_element_set_state (udpsrc0, GST_STATE_NULL);
843 gst_object_unref (udpsrc0);
847 goto no_udp_protocol;
850 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
851 #if 0 //Changes for testing with dongle
852 /* check if port is even */
853 if ((tmp_rtp & 1) != 0) {
854 /* port not even, close and allocate another */
858 gst_element_set_state (udpsrc0, GST_STATE_NULL);
859 gst_object_unref (udpsrc0);
865 /* allocate port+1 for RTCP now */
866 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
868 goto no_udp_rtcp_protocol;
871 tmp_rtcp = tmp_rtp + 1;
872 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
874 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
875 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
876 if (ret == GST_STATE_CHANGE_FAILURE) {
881 gst_element_set_state (udpsrc0, GST_STATE_NULL);
882 gst_object_unref (udpsrc0);
884 gst_element_set_state (udpsrc1, GST_STATE_NULL);
885 gst_object_unref (udpsrc1);
891 /* all fine, do port check */
892 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
893 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
895 /* this should not happen... */
896 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
899 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
901 goto no_udp_protocol;
903 g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL);
904 g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL);
905 g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL);
907 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
909 goto no_udp_protocol;
911 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
912 "send-duplicates")) {
913 g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
914 g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
915 stream->filter_duplicates = FALSE;
917 GST_WARNING ("multiudpsink version found without send-duplicates property");
918 stream->filter_duplicates = TRUE;
921 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
923 //g_object_set (G_OBJECT (udpsink0), "buffer-size", 0x80000, NULL);
924 g_object_set (G_OBJECT (udpsink0), "buffer-size", 200, NULL);
926 GST_WARNING ("multiudpsink version found without buffer-size property");
929 g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
930 g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL);
931 g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL);
932 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
933 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
935 g_print ("\n\n\n\tsetting sync to false\n\n\n");
936 g_object_set (G_OBJECT (udpsink0), "sync", FALSE, NULL);
939 g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
940 g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL);
941 g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL);
942 g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL);
944 /* we keep these elements, we configure all in configure_transport when the
945 * server told us to really use the UDP ports. */
946 stream->udpsrc[0] = udpsrc0;
947 stream->udpsrc[1] = udpsrc1;
948 stream->udpsink[0] = udpsink0;
949 stream->udpsink[1] = udpsink1;
950 stream->server_port.min = rtpport;
951 #if 1 //Changes for testing with dongle
952 stream->server_port.max = rtcpport;
954 stream->server_port.max = -1;
967 no_udp_rtcp_protocol:
978 gst_element_set_state (udpsrc0, GST_STATE_NULL);
979 gst_object_unref (udpsrc0);
982 gst_element_set_state (udpsrc1, GST_STATE_NULL);
983 gst_object_unref (udpsrc1);
986 gst_element_set_state (udpsink0, GST_STATE_NULL);
987 gst_object_unref (udpsink0);
990 gst_element_set_state (udpsink1, GST_STATE_NULL);
991 gst_object_unref (udpsink1);
997 /* executed from streaming thread */
999 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPMediaStream * stream)
1002 GstCaps *newcaps, *oldcaps;
1004 if ((newcaps = gst_pad_get_current_caps (pad)))
1005 gst_caps_ref (newcaps);
1007 oldcaps = stream->caps;
1008 stream->caps = newcaps;
1011 gst_caps_unref (oldcaps);
1013 capsstr = gst_caps_to_string (newcaps);
1014 GST_INFO ("stream %p received caps %p, %s", stream, newcaps, capsstr);
1019 dump_structure (const GstStructure * s)
1023 sstr = gst_structure_to_string (s);
1024 GST_INFO ("structure: %s", sstr);
1028 static GstRTSPMediaTrans *
1029 find_transport (GstRTSPMediaStream * stream, const gchar * rtcp_from)
1032 GstRTSPMediaTrans *result = NULL;
1037 if (rtcp_from == NULL)
1040 tmp = g_strrstr (rtcp_from, ":");
1044 port = atoi (tmp + 1);
1045 dest = g_strndup (rtcp_from, tmp - rtcp_from);
1047 GST_INFO ("finding %s:%d", dest, port);
1049 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
1050 GstRTSPMediaTrans *trans = walk->data;
1053 min = trans->transport->client_port.min;
1054 max = trans->transport->client_port.max;
1056 if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
1068 on_new_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1070 GstStructure *stats;
1071 GstRTSPMediaTrans *trans;
1073 GST_INFO ("%p: new source %p", stream, source);
1075 /* see if we have a stream to match with the origin of the RTCP packet */
1076 trans = g_object_get_qdata (source, ssrc_stream_map_key);
1077 if (trans == NULL) {
1078 g_object_get (source, "stats", &stats, NULL);
1080 const gchar *rtcp_from;
1082 dump_structure (stats);
1084 rtcp_from = gst_structure_get_string (stats, "rtcp-from");
1085 if ((trans = find_transport (stream, rtcp_from))) {
1086 GST_INFO ("%p: found transport %p for source %p", stream, trans,
1089 /* keep ref to the source */
1090 trans->rtpsource = source;
1092 g_object_set_qdata (source, ssrc_stream_map_key, trans);
1094 gst_structure_free (stats);
1097 GST_INFO ("%p: source %p for transport %p", stream, source, trans);
1102 on_ssrc_sdes (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1104 GST_INFO ("%p: new SDES %p", stream, source);
1108 on_ssrc_active (GObject * session, GObject * source,
1109 GstRTSPMediaStream * stream)
1111 GstRTSPMediaTrans *trans;
1113 trans = g_object_get_qdata (source, ssrc_stream_map_key);
1115 GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
1117 if (trans && trans->keep_alive)
1118 trans->keep_alive (trans->ka_user_data);
1122 GstStructure *stats;
1123 g_object_get (source, "stats", &stats, NULL);
1125 dump_structure (stats);
1126 gst_structure_free (stats);
1133 on_bye_ssrc (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1135 GST_INFO ("%p: source %p bye", stream, source);
1139 on_bye_timeout (GObject * session, GObject * source,
1140 GstRTSPMediaStream * stream)
1142 GstRTSPMediaTrans *trans;
1144 GST_INFO ("%p: source %p bye timeout", stream, source);
1146 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
1147 trans->rtpsource = NULL;
1148 trans->timeout = TRUE;
1153 on_timeout (GObject * session, GObject * source, GstRTSPMediaStream * stream)
1155 GstRTSPMediaTrans *trans;
1157 GST_INFO ("%p: source %p timeout", stream, source);
1159 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
1160 trans->rtpsource = NULL;
1161 trans->timeout = TRUE;
1165 static GstFlowReturn
1166 handle_new_sample (GstAppSink * sink, gpointer user_data)
1171 GstRTSPMediaStream *stream;
1173 sample = gst_app_sink_pull_sample(sink);
1177 buffer = gst_sample_get_buffer(sample);
1180 gst_sample_unref(sample);
1184 stream = (GstRTSPMediaStream *) user_data;
1186 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
1187 GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data;
1189 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
1191 tr->send_rtp (buffer, tr->transport->port.min, tr->user_data);
1195 tr->send_rtcp (buffer, tr->transport->port.max, tr->user_data);
1198 gst_buffer_unref (buffer);
1199 gst_sample_unref (sample);
1204 static GstAppSinkCallbacks sink_cb = {
1205 NULL, /* not interested in EOS */
1206 NULL, /* not interested in preroll buffers */
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 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsink[i]);
1238 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->appsrc[i]);
1239 gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
1240 &sink_cb, stream, NULL);
1243 /* hook up the stream to the RTP session elements. */
1244 name = g_strdup_printf ("send_rtp_sink_%d", idx);
1245 stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
1247 name = g_strdup_printf ("send_rtp_src_%d", idx);
1248 stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name);
1250 name = g_strdup_printf ("send_rtcp_src_%d", idx);
1251 stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name);
1253 name = g_strdup_printf ("recv_rtcp_sink_%d", idx);
1254 stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name);
1256 name = g_strdup_printf ("recv_rtp_sink_%d", idx);
1257 stream->recv_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
1260 /* get the session */
1261 g_signal_emit_by_name (media->rtpbin, "get-internal-session", idx,
1264 g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
1266 g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
1268 g_signal_connect (stream->session, "on-ssrc-active",
1269 (GCallback) on_ssrc_active, stream);
1270 g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
1272 g_signal_connect (stream->session, "on-bye-timeout",
1273 (GCallback) on_bye_timeout, stream);
1274 g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
1277 /* link the RTP pad to the session manager */
1278 ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
1279 if (ret != GST_PAD_LINK_OK)
1282 /* make tee for RTP and link to stream */
1283 stream->tee[0] = gst_element_factory_make ("tee", NULL);
1284 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[0]);
1286 pad = gst_element_get_static_pad (stream->tee[0], "sink");
1287 gst_pad_link (stream->send_rtp_src, pad);
1288 gst_object_unref (pad);
1290 /* link RTP sink, we're pretty sure this will work. */
1291 teepad = gst_element_get_request_pad (stream->tee[0], "src%d");
1292 pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
1293 gst_pad_link (teepad, pad);
1294 gst_object_unref (pad);
1295 gst_object_unref (teepad);
1297 teepad = gst_element_get_request_pad (stream->tee[0], "src%d");
1298 pad = gst_element_get_static_pad (stream->appsink[0], "sink");
1299 gst_pad_link (teepad, pad);
1300 gst_object_unref (pad);
1301 gst_object_unref (teepad);
1303 /* make tee for RTCP */
1304 stream->tee[1] = gst_element_factory_make ("tee", NULL);
1305 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->tee[1]);
1307 pad = gst_element_get_static_pad (stream->tee[1], "sink");
1308 gst_pad_link (stream->send_rtcp_src, pad);
1309 gst_object_unref (pad);
1311 /* link RTCP elements */
1312 teepad = gst_element_get_request_pad (stream->tee[1], "src%d");
1313 pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
1314 gst_pad_link (teepad, pad);
1315 gst_object_unref (pad);
1316 gst_object_unref (teepad);
1318 teepad = gst_element_get_request_pad (stream->tee[1], "src%d");
1319 pad = gst_element_get_static_pad (stream->appsink[1], "sink");
1320 gst_pad_link (teepad, pad);
1321 gst_object_unref (pad);
1322 gst_object_unref (teepad);
1324 /* make selector for the RTP receivers */
1325 stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL);
1326 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
1328 pad = gst_element_get_static_pad (stream->selector[0], "src");
1329 gst_pad_link (pad, stream->recv_rtp_sink);
1330 gst_object_unref (pad);
1332 selpad = gst_element_get_request_pad (stream->selector[0], "sink%d");
1333 pad = gst_element_get_static_pad (stream->udpsrc[0], "src");
1334 gst_pad_link (pad, selpad);
1335 gst_object_unref (pad);
1336 gst_object_unref (selpad);
1338 selpad = gst_element_get_request_pad (stream->selector[0], "sink%d");
1339 pad = gst_element_get_static_pad (stream->appsrc[0], "src");
1340 gst_pad_link (pad, selpad);
1341 gst_object_unref (pad);
1342 gst_object_unref (selpad);
1344 /* make selector for the RTCP receivers */
1345 stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL);
1346 gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
1348 pad = gst_element_get_static_pad (stream->selector[1], "src");
1349 gst_pad_link (pad, stream->recv_rtcp_sink);
1350 gst_object_unref (pad);
1352 selpad = gst_element_get_request_pad (stream->selector[1], "sink%d");
1353 pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
1354 gst_pad_link (pad, selpad);
1355 gst_object_unref (pad);
1356 gst_object_unref (selpad);
1358 selpad = gst_element_get_request_pad (stream->selector[1], "sink%d");
1359 pad = gst_element_get_static_pad (stream->appsrc[1], "src");
1360 gst_pad_link (pad, selpad);
1361 gst_object_unref (pad);
1362 gst_object_unref (selpad);
1364 /* we set and keep these to playing so that they don't cause NO_PREROLL return
1366 gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING);
1367 gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING);
1368 gst_element_set_locked_state (stream->udpsrc[0], TRUE);
1369 gst_element_set_locked_state (stream->udpsrc[1], TRUE);
1371 /* be notified of caps changes */
1372 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
1373 (GCallback) caps_notify, stream);
1375 stream->prepared = TRUE;
1382 GST_WARNING ("failed to link stream %d", idx);
1388 unlock_streams (GstRTSPMedia * media)
1392 /* unlock the udp src elements */
1393 n_streams = gst_rtsp_media_n_streams (media);
1394 for (i = 0; i < n_streams; i++) {
1395 GstRTSPMediaStream *stream;
1397 stream = gst_rtsp_media_get_stream (media, i);
1399 gst_element_set_locked_state (stream->udpsrc[0], FALSE);
1400 gst_element_set_locked_state (stream->udpsrc[1], FALSE);
1405 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
1407 g_mutex_lock (media->lock);
1408 /* never overwrite the error status */
1409 if (media->status != GST_RTSP_MEDIA_STATUS_ERROR)
1410 media->status = status;
1411 GST_DEBUG ("setting new status to %d", status);
1412 g_cond_broadcast (media->cond);
1413 g_mutex_unlock (media->lock);
1416 static GstRTSPMediaStatus
1417 gst_rtsp_media_get_status (GstRTSPMedia * media)
1419 GstRTSPMediaStatus result;
1422 g_mutex_lock (media->lock);
1423 g_get_current_time (&timeout);
1424 g_time_val_add (&timeout, 20 * G_USEC_PER_SEC);
1425 /* while we are preparing, wait */
1426 while (media->status == GST_RTSP_MEDIA_STATUS_PREPARING) {
1427 GST_DEBUG ("waiting for status change");
1428 if (!g_cond_timed_wait (media->cond, media->lock, &timeout)) {
1429 GST_DEBUG ("timeout, assuming error status");
1430 media->status = GST_RTSP_MEDIA_STATUS_ERROR;
1433 /* could be success or error */
1434 result = media->status;
1435 GST_DEBUG ("got status %d", result);
1436 g_mutex_unlock (media->lock);
1442 default_handle_message (GstRTSPMedia * media, GstMessage * message)
1444 GstMessageType type;
1446 type = GST_MESSAGE_TYPE (message);
1449 case GST_MESSAGE_STATE_CHANGED:
1451 case GST_MESSAGE_BUFFERING:
1455 gst_message_parse_buffering (message, &percent);
1457 /* no state management needed for live pipelines */
1461 if (percent == 100) {
1462 /* a 100% message means buffering is done */
1463 media->buffering = FALSE;
1464 /* if the desired state is playing, go back */
1465 if (media->target_state == GST_STATE_PLAYING) {
1466 GST_INFO ("Buffering done, setting pipeline to PLAYING");
1467 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1469 GST_INFO ("Buffering done");
1472 /* buffering busy */
1473 if (media->buffering == FALSE) {
1474 if (media->target_state == GST_STATE_PLAYING) {
1475 /* we were not buffering but PLAYING, PAUSE the pipeline. */
1476 GST_INFO ("Buffering, setting pipeline to PAUSED ...");
1477 gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1479 GST_INFO ("Buffering ...");
1482 media->buffering = TRUE;
1486 case GST_MESSAGE_LATENCY:
1488 gst_bin_recalculate_latency (GST_BIN_CAST (media->pipeline));
1491 case GST_MESSAGE_ERROR:
1496 //g_print ("\n\n\n\n\n++++++++++++++++Generating dot file ++++++++++++++\n\n\n\n");
1498 GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN_CAST(media->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "wfd-error");
1500 gst_message_parse_error (message, &gerror, &debug);
1502 GST_ERROR ("%p: got error %s (%s)", media, gerror->message, debug);
1503 g_error_free (gerror);
1506 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
1509 case GST_MESSAGE_WARNING:
1514 gst_message_parse_warning (message, &gerror, &debug);
1515 GST_WARNING ("%p: got warning %s (%s)", media, gerror->message, debug);
1516 g_error_free (gerror);
1520 case GST_MESSAGE_ELEMENT:
1522 case GST_MESSAGE_STREAM_STATUS:
1524 case GST_MESSAGE_ASYNC_DONE:
1525 if (!media->adding) {
1526 /* when we are dynamically adding pads, the addition of the udpsrc will
1527 * temporarily produce ASYNC_DONE messages. We have to ignore them and
1528 * wait for the final ASYNC_DONE after everything prerolled */
1529 GST_INFO ("%p: got ASYNC_DONE", media);
1530 collect_media_stats (media);
1531 //GST_INFO ("Setting again to PAUSED state....");
1532 //gst_element_set_state (media->pipeline, GST_STATE_PAUSED); // commented on 29/06/12 to test resume
1533 gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
1535 GST_INFO ("%p: ignoring ASYNC_DONE", media);
1538 case GST_MESSAGE_EOS:
1539 GST_INFO ("%p: got EOS", media);
1540 if (media->eos_pending) {
1541 GST_DEBUG ("shutting down after EOS");
1542 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1543 media->eos_pending = FALSE;
1544 g_object_unref (media);
1548 GST_INFO ("%p: got message type %s", media,
1549 gst_message_type_get_name (type));
1556 bus_message (GstBus * bus, GstMessage * message, GstRTSPMedia * media)
1558 GstRTSPMediaClass *klass;
1561 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1563 if (klass->handle_message)
1564 ret = klass->handle_message (media, message);
1571 /* called from streaming threads */
1573 pad_added_cb (GstElement * element, GstPad * pad, GstRTSPMedia * media)
1575 GstRTSPMediaStream *stream;
1579 i = media->streams->len + 1;
1581 GST_INFO ("pad added %s:%s, stream %d", GST_DEBUG_PAD_NAME (pad), i);
1583 stream = g_new0 (GstRTSPMediaStream, 1);
1584 stream->payloader = element;
1586 name = g_strdup_printf ("dynpay%d", i);
1588 media->adding = TRUE;
1590 /* ghost the pad of the payloader to the element */
1591 stream->srcpad = gst_ghost_pad_new (name, pad);
1592 gst_pad_set_active (stream->srcpad, TRUE);
1593 gst_element_add_pad (media->element, stream->srcpad);
1596 /* add stream now */
1597 g_array_append_val (media->streams, stream);
1599 setup_stream (stream, i, media);
1601 for (i = 0; i < 2; i++) {
1602 gst_element_set_state (stream->udpsink[i], GST_STATE_PAUSED);
1603 gst_element_set_state (stream->appsink[i], GST_STATE_PAUSED);
1604 gst_element_set_state (stream->tee[i], GST_STATE_PAUSED);
1605 gst_element_set_state (stream->selector[i], GST_STATE_PAUSED);
1606 gst_element_set_state (stream->appsrc[i], GST_STATE_PAUSED);
1608 media->adding = FALSE;
1612 no_more_pads_cb (GstElement * element, GstRTSPMedia * media)
1614 GST_INFO ("no more pads");
1615 if (media->fakesink) {
1616 gst_object_ref (media->fakesink);
1617 gst_bin_remove (GST_BIN (media->pipeline), media->fakesink);
1618 gst_element_set_state (media->fakesink, GST_STATE_NULL);
1619 gst_object_unref (media->fakesink);
1620 media->fakesink = NULL;
1621 GST_INFO ("removed fakesink");
1626 * gst_rtsp_media_prepare:
1627 * @media: a #GstRTSPMedia
1629 * Prepare @media for streaming. This function will create the pipeline and
1630 * other objects to manage the streaming.
1632 * It will preroll the pipeline and collect vital information about the streams
1633 * such as the duration.
1635 * Returns: %TRUE on success.
1638 gst_rtsp_media_prepare (GstRTSPMedia * media)
1640 GstStateChangeReturn ret;
1641 GstRTSPMediaStatus status;
1643 GstRTSPMediaClass *klass;
1647 if (media->status == GST_RTSP_MEDIA_STATUS_PREPARED)
1650 if (!media->reusable && media->reused)
1653 GST_INFO ("preparing media %p", media);
1655 /* reset some variables */
1656 media->is_live = FALSE;
1657 media->buffering = FALSE;
1658 /* we're preparing now */
1659 media->status = GST_RTSP_MEDIA_STATUS_PREPARING;
1661 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (media->pipeline));
1663 /* add the pipeline bus to our custom mainloop */
1664 media->source = gst_bus_create_watch (bus);
1665 gst_object_unref (bus);
1667 g_source_set_callback (media->source, (GSourceFunc) bus_message, media, NULL);
1669 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1670 media->id = g_source_attach (media->source, klass->context);
1672 media->rtpbin = gst_element_factory_make ("gstrtpbin", NULL);
1673 g_object_set (media->rtpbin, "latency", 0, NULL);
1675 g_print ("\n\nset latency to zero for rtpbin\n\n\n");
1677 /* add stuff to the bin */
1678 gst_bin_add (GST_BIN (media->pipeline), media->rtpbin);
1680 /* link streams we already have, other streams might appear when we have
1681 * dynamic elements */
1682 n_streams = gst_rtsp_media_n_streams (media);
1683 for (i = 0; i < n_streams; i++) {
1684 GstRTSPMediaStream *stream;
1686 stream = gst_rtsp_media_get_stream (media, i);
1688 setup_stream (stream, i, media);
1691 for (walk = media->dynamic; walk; walk = g_list_next (walk)) {
1692 GstElement *elem = walk->data;
1694 GST_INFO ("adding callbacks for dynamic element %p", elem);
1696 g_signal_connect (elem, "pad-added", (GCallback) pad_added_cb, media);
1697 g_signal_connect (elem, "no-more-pads", (GCallback) no_more_pads_cb, media);
1699 /* we add a fakesink here in order to make the state change async. We remove
1700 * the fakesink again in the no-more-pads callback. */
1701 media->fakesink = gst_element_factory_make ("fakesink", "fakesink");
1702 gst_bin_add (GST_BIN (media->pipeline), media->fakesink);
1705 GST_INFO ("setting pipeline to PAUSED for media %p", media);
1706 /* first go to PAUSED */
1707 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
1708 media->target_state = GST_STATE_PAUSED;
1711 case GST_STATE_CHANGE_SUCCESS:
1712 GST_INFO ("SUCCESS state change for media %p", media);
1714 case GST_STATE_CHANGE_ASYNC:
1715 GST_INFO ("ASYNC state change for media %p", media);
1717 case GST_STATE_CHANGE_NO_PREROLL:
1718 /* we need to go to PLAYING */
1719 GST_INFO ("NO_PREROLL state change: live media %p", media);
1720 media->is_live = TRUE;
1721 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1722 if (ret == GST_STATE_CHANGE_FAILURE)
1725 case GST_STATE_CHANGE_FAILURE:
1729 /* now wait for all pads to be prerolled */
1730 //GST_DEBUG_BIN_TO_DOT_FILE(media->pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "test-server-arch");
1732 status = gst_rtsp_media_get_status (media);
1733 if (status == GST_RTSP_MEDIA_STATUS_ERROR)
1736 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
1738 GST_INFO ("object %p is prerolled", media);
1750 GST_WARNING ("can not reuse media %p", media);
1755 GST_WARNING ("failed to preroll pipeline");
1756 unlock_streams (media);
1757 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1758 gst_rtsp_media_unprepare (media);
1764 * gst_rtsp_media_unprepare:
1765 * @media: a #GstRTSPMedia
1767 * Unprepare @media. After this call, the media should be prepared again before
1768 * it can be used again. If the media is set to be non-reusable, a new instance
1771 * Returns: %TRUE on success.
1774 gst_rtsp_media_unprepare (GstRTSPMedia * media)
1776 GstRTSPMediaClass *klass;
1779 if (media->status == GST_RTSP_MEDIA_STATUS_UNPREPARED)
1782 GST_INFO ("unprepare media %p", media);
1783 media->target_state = GST_STATE_NULL;
1785 klass = GST_RTSP_MEDIA_GET_CLASS (media);
1786 if (klass->unprepare)
1787 success = klass->unprepare (media);
1791 media->status = GST_RTSP_MEDIA_STATUS_UNPREPARED;
1792 media->reused = TRUE;
1794 /* when the media is not reusable, this will effectively unref the media and
1796 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARED], 0, NULL);
1802 default_unprepare (GstRTSPMedia * media)
1804 if (media->eos_shutdown) {
1805 GST_DEBUG ("sending EOS for shutdown");
1806 /* ref so that we don't disappear */
1807 g_object_ref (media);
1808 media->eos_pending = TRUE;
1809 gst_element_send_event (media->pipeline, gst_event_new_eos ());
1810 /* we need to go to playing again for the EOS to propagate, normally in this
1811 * state, nothing is receiving data from us anymore so this is ok. */
1812 gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
1814 GST_DEBUG ("shutting down");
1815 gst_element_set_state (media->pipeline, GST_STATE_NULL);
1821 add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
1822 gchar * dest, gint min, gint max)
1824 gboolean do_add = TRUE;
1825 RTSPDestination *ndest;
1827 if (stream->filter_duplicates) {
1828 RTSPDestination fdest;
1835 /* first see if we already added this destination */
1837 g_list_find_custom (stream->destinations, &fdest,
1838 (GCompareFunc) dest_compare);
1840 ndest = (RTSPDestination *) find->data;
1842 GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max,
1850 GST_INFO ("adding %s:%d-%d", dest, min, max);
1851 g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
1852 g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
1854 if (stream->filter_duplicates) {
1855 ndest = create_destination (dest, min, max);
1856 stream->destinations = g_list_prepend (stream->destinations, ndest);
1862 remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
1863 gchar * dest, gint min, gint max)
1865 gboolean do_remove = TRUE;
1866 RTSPDestination *ndest = NULL;
1869 if (stream->filter_duplicates) {
1870 RTSPDestination fdest;
1876 /* first see if we already added this destination */
1878 g_list_find_custom (stream->destinations, &fdest,
1879 (GCompareFunc) dest_compare);
1883 ndest = (RTSPDestination *) find->data;
1884 if (--ndest->count > 0) {
1886 GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max,
1892 GST_INFO ("removing %s:%d-%d", dest, min, max);
1893 g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
1894 g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
1896 if (stream->filter_duplicates) {
1897 stream->destinations = g_list_delete_link (stream->destinations, find);
1899 free_destination (ndest);
1905 * gst_rtsp_media_set_state:
1906 * @media: a #GstRTSPMedia
1907 * @state: the target state of the media
1908 * @transports: a #GArray of #GstRTSPMediaTrans pointers
1910 * Set the state of @media to @state and for the transports in @transports.
1912 * Returns: %TRUE on success.
1915 gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
1916 GArray * transports)
1919 GstStateChangeReturn ret;
1920 gboolean add, remove, do_state;
1923 g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
1924 g_return_val_if_fail (transports != NULL, FALSE);
1926 /* NULL and READY are the same */
1927 if (state == GST_STATE_READY)
1928 state = GST_STATE_NULL;
1930 add = remove = FALSE;
1932 GST_INFO ("going to state %s media %p", gst_element_state_get_name (state),
1936 case GST_STATE_NULL:
1937 /* unlock the streams so that they follow the state changes from now on */
1938 unlock_streams (media);
1940 case GST_STATE_PAUSED:
1941 /* we're going from PLAYING to PAUSED, READY or NULL, remove */
1942 if (media->target_state == GST_STATE_PLAYING)
1945 case GST_STATE_PLAYING:
1946 /* we're going to PLAYING, add */
1952 old_active = media->active;
1954 for (i = 0; i < transports->len; i++) {
1955 GstRTSPMediaTrans *tr;
1956 GstRTSPMediaStream *stream;
1957 GstRTSPTransport *trans;
1959 /* we need a non-NULL entry in the array */
1960 tr = g_array_index (transports, GstRTSPMediaTrans *, i);
1964 /* we need a transport */
1965 if (!(trans = tr->transport))
1968 /* get the stream and add the destinations */
1969 stream = gst_rtsp_media_get_stream (media, tr->idx);
1970 switch (trans->lower_transport) {
1971 case GST_RTSP_LOWER_TRANS_UDP:
1972 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1977 dest = trans->destination;
1978 if (trans->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1979 min = trans->port.min;
1980 max = trans->port.max;
1982 min = trans->client_port.min;
1983 max = trans->client_port.max;
1986 if (add && !tr->active) {
1987 add_udp_destination (media, stream, dest, min, max);
1988 stream->transports = g_list_prepend (stream->transports, tr);
1991 } else if (remove && tr->active) {
1992 remove_udp_destination (media, stream, dest, min, max);
1993 stream->transports = g_list_remove (stream->transports, tr);
1999 case GST_RTSP_LOWER_TRANS_TCP:
2000 if (add && !tr->active) {
2001 GST_INFO ("adding TCP %s", trans->destination);
2002 stream->transports = g_list_prepend (stream->transports, tr);
2005 } else if (remove && tr->active) {
2006 GST_INFO ("removing TCP %s", trans->destination);
2007 stream->transports = g_list_remove (stream->transports, tr);
2013 GST_INFO ("Unknown transport %d", trans->lower_transport);
2018 /* we just added the first media, do the playing state change */
2019 if (old_active == 0 && add)
2021 /* if we have no more active media, do the downward state changes */
2022 else if (media->active == 0)
2027 GST_INFO ("state %d active %d media %p do_state %d", state, media->active,
2030 if (media->target_state != state) {
2032 if (state == GST_STATE_NULL) {
2033 gst_rtsp_media_unprepare (media);
2035 GST_INFO ("state %s media %p", gst_element_state_get_name (state),
2037 media->target_state = state;
2038 ret = gst_element_set_state (media->pipeline, state);
2041 g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
2045 /* remember where we are */
2046 if (state == GST_STATE_PAUSED || old_active != media->active)
2047 collect_media_stats (media);
2053 * gst_rtsp_media_remove_elements:
2054 * @media: a #GstRTSPMedia
2056 * Remove all elements and the pipeline controlled by @media.
2059 gst_rtsp_media_remove_elements (GstRTSPMedia * media)
2063 unlock_streams (media);
2065 for (i = 0; i < media->streams->len; i++) {
2066 GstRTSPMediaStream *stream;
2068 GST_INFO ("Removing elements of stream %d from pipeline", i);
2070 stream = g_array_index (media->streams, GstRTSPMediaStream *, i);
2072 gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
2074 g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
2076 for (j = 0; j < 2; j++) {
2077 gst_element_set_state (stream->udpsrc[j], GST_STATE_NULL);
2078 gst_element_set_state (stream->udpsink[j], GST_STATE_NULL);
2079 gst_element_set_state (stream->appsrc[j], GST_STATE_NULL);
2080 gst_element_set_state (stream->appsink[j], GST_STATE_NULL);
2081 gst_element_set_state (stream->tee[j], GST_STATE_NULL);
2082 gst_element_set_state (stream->selector[j], GST_STATE_NULL);
2084 gst_bin_remove (GST_BIN (media->pipeline), stream->udpsrc[j]);
2085 gst_bin_remove (GST_BIN (media->pipeline), stream->udpsink[j]);
2086 gst_bin_remove (GST_BIN (media->pipeline), stream->appsrc[j]);
2087 gst_bin_remove (GST_BIN (media->pipeline), stream->appsink[j]);
2088 gst_bin_remove (GST_BIN (media->pipeline), stream->tee[j]);
2089 gst_bin_remove (GST_BIN (media->pipeline), stream->selector[j]);
2092 gst_caps_unref (stream->caps);
2093 stream->caps = NULL;
2094 gst_rtsp_media_stream_free (stream);
2096 g_array_remove_range (media->streams, 0, media->streams->len);
2098 gst_element_set_state (media->rtpbin, GST_STATE_NULL);
2099 gst_bin_remove (GST_BIN (media->pipeline), media->rtpbin);
2101 gst_object_unref (media->pipeline);
2102 media->pipeline = NULL;