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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
25 #include <gst/app/gstappsrc.h>
26 #include <gst/app/gstappsink.h>
28 #include "rtsp-stream.h"
36 GST_DEBUG_CATEGORY_STATIC (rtsp_stream_debug);
37 #define GST_CAT_DEFAULT rtsp_stream_debug
39 static GQuark ssrc_stream_map_key;
41 static void gst_rtsp_stream_finalize (GObject * obj);
43 G_DEFINE_TYPE (GstRTSPStream, gst_rtsp_stream, G_TYPE_OBJECT);
46 gst_rtsp_stream_class_init (GstRTSPStreamClass * klass)
48 GObjectClass *gobject_class;
50 gobject_class = G_OBJECT_CLASS (klass);
52 gobject_class->finalize = gst_rtsp_stream_finalize;
54 GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream");
56 ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
60 gst_rtsp_stream_init (GstRTSPStream * media)
65 gst_rtsp_stream_finalize (GObject * obj)
67 GstRTSPStream *stream;
69 stream = GST_RTSP_STREAM (obj);
71 /* we really need to be unjoined now */
72 g_return_if_fail (!stream->is_joined);
74 gst_object_unref (stream->payloader);
75 gst_object_unref (stream->srcpad);
77 G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj);
81 * gst_rtsp_stream_new:
84 * @payloader: a #GstElement
86 * Create a new media stream with index @idx that handles RTP data on
87 * @srcpad and has a payloader element @payloader.
89 * Returns: a new #GstRTSPStream
92 gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad)
94 GstRTSPStream *stream;
96 g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
97 g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
98 g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
100 stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL);
102 stream->payloader = gst_object_ref (payloader);
103 stream->srcpad = gst_object_ref (srcpad);
109 * gst_rtsp_stream_set_mtu:
110 * @stream: a #GstRTSPStream
113 * Configure the mtu in the payloader of @stream to @mtu.
116 gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu)
118 g_return_if_fail (GST_IS_RTSP_STREAM (stream));
120 g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL);
124 * gst_rtsp_stream_get_mtu:
125 * @stream: a #GstRTSPStream
127 * Get the configured MTU in the payloader of @stream.
129 * Returns: the MTU of the payloader.
132 gst_rtsp_stream_get_mtu (GstRTSPStream * stream)
136 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0);
138 g_object_get (G_OBJECT (stream->payloader), "mtu", &mtu, NULL);
144 alloc_ports (GstRTSPStream * stream)
146 GstStateChangeReturn ret;
147 GstElement *udpsrc0, *udpsrc1;
148 GstElement *udpsink0, *udpsink1;
149 gint tmp_rtp, tmp_rtcp;
151 gint rtpport, rtcpport;
155 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
163 /* Start with random port */
167 host = "udp://[::0]";
169 host = "udp://0.0.0.0";
171 /* try to allocate 2 UDP ports, the RTP port should be an even
172 * number and the RTCP port should be the next (uneven) port */
174 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
176 goto no_udp_protocol;
177 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
179 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
180 if (ret == GST_STATE_CHANGE_FAILURE) {
186 gst_element_set_state (udpsrc0, GST_STATE_NULL);
187 gst_object_unref (udpsrc0);
191 goto no_udp_protocol;
194 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
196 /* check if port is even */
197 if ((tmp_rtp & 1) != 0) {
198 /* port not even, close and allocate another */
202 gst_element_set_state (udpsrc0, GST_STATE_NULL);
203 gst_object_unref (udpsrc0);
209 /* allocate port+1 for RTCP now */
210 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
212 goto no_udp_rtcp_protocol;
215 tmp_rtcp = tmp_rtp + 1;
216 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
218 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
219 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
220 if (ret == GST_STATE_CHANGE_FAILURE) {
225 gst_element_set_state (udpsrc0, GST_STATE_NULL);
226 gst_object_unref (udpsrc0);
228 gst_element_set_state (udpsrc1, GST_STATE_NULL);
229 gst_object_unref (udpsrc1);
234 /* all fine, do port check */
235 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
236 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
238 /* this should not happen... */
239 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
242 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
244 goto no_udp_protocol;
246 g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL);
247 g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL);
248 g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL);
250 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
252 goto no_udp_protocol;
254 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
255 "send-duplicates")) {
256 g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
257 g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
260 ("old multiudpsink version found without send-duplicates property");
263 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
265 g_object_set (G_OBJECT (udpsink0), "buffer-size", stream->buffer_size,
268 GST_WARNING ("multiudpsink version found without buffer-size property");
271 g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL);
272 g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL);
273 g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL);
274 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
275 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
276 g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
277 g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL);
278 g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL);
279 g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL);
281 /* we keep these elements, we will further configure them when the
282 * client told us to really use the UDP ports. */
283 stream->udpsrc[0] = udpsrc0;
284 stream->udpsrc[1] = udpsrc1;
285 stream->udpsink[0] = udpsink0;
286 stream->udpsink[1] = udpsink1;
287 stream->server_port.min = rtpport;
288 stream->server_port.max = rtcpport;
301 no_udp_rtcp_protocol:
312 gst_element_set_state (udpsrc0, GST_STATE_NULL);
313 gst_object_unref (udpsrc0);
316 gst_element_set_state (udpsrc1, GST_STATE_NULL);
317 gst_object_unref (udpsrc1);
320 gst_element_set_state (udpsink0, GST_STATE_NULL);
321 gst_object_unref (udpsink0);
324 gst_element_set_state (udpsink1, GST_STATE_NULL);
325 gst_object_unref (udpsink1);
331 /* executed from streaming thread */
333 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream)
335 GstCaps *newcaps, *oldcaps;
337 newcaps = gst_pad_get_current_caps (pad);
339 oldcaps = stream->caps;
340 stream->caps = newcaps;
343 gst_caps_unref (oldcaps);
345 GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps,
350 dump_structure (const GstStructure * s)
354 sstr = gst_structure_to_string (s);
355 GST_INFO ("structure: %s", sstr);
359 static GstRTSPStreamTransport *
360 find_transport (GstRTSPStream * stream, const gchar * rtcp_from)
363 GstRTSPStreamTransport *result = NULL;
368 if (rtcp_from == NULL)
371 tmp = g_strrstr (rtcp_from, ":");
375 port = atoi (tmp + 1);
376 dest = g_strndup (rtcp_from, tmp - rtcp_from);
378 GST_INFO ("finding %s:%d in %d transports", dest, port,
379 g_list_length (stream->transports));
381 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
382 GstRTSPStreamTransport *trans = walk->data;
385 min = trans->transport->client_port.min;
386 max = trans->transport->client_port.max;
388 if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
399 static GstRTSPStreamTransport *
400 check_transport (GObject * source, GstRTSPStream * stream)
403 GstRTSPStreamTransport *trans;
405 /* see if we have a stream to match with the origin of the RTCP packet */
406 trans = g_object_get_qdata (source, ssrc_stream_map_key);
408 g_object_get (source, "stats", &stats, NULL);
410 const gchar *rtcp_from;
412 dump_structure (stats);
414 rtcp_from = gst_structure_get_string (stats, "rtcp-from");
415 if ((trans = find_transport (stream, rtcp_from))) {
416 GST_INFO ("%p: found transport %p for source %p", stream, trans,
419 /* keep ref to the source */
420 trans->rtpsource = source;
422 g_object_set_qdata (source, ssrc_stream_map_key, trans);
424 gst_structure_free (stats);
433 on_new_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
435 GstRTSPStreamTransport *trans;
437 GST_INFO ("%p: new source %p", stream, source);
439 trans = check_transport (source, stream);
442 GST_INFO ("%p: source %p for transport %p", stream, source, trans);
446 on_ssrc_sdes (GObject * session, GObject * source, GstRTSPStream * stream)
448 GST_INFO ("%p: new SDES %p", stream, source);
452 on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream)
454 GstRTSPStreamTransport *trans;
456 trans = check_transport (source, stream);
459 GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
461 if (trans && trans->keep_alive)
462 trans->keep_alive (trans->ka_user_data);
467 g_object_get (source, "stats", &stats, NULL);
469 dump_structure (stats);
470 gst_structure_free (stats);
477 on_bye_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
479 GST_INFO ("%p: source %p bye", stream, source);
483 on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
485 GstRTSPStreamTransport *trans;
487 GST_INFO ("%p: source %p bye timeout", stream, source);
489 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
490 trans->rtpsource = NULL;
491 trans->timeout = TRUE;
496 on_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
498 GstRTSPStreamTransport *trans;
500 GST_INFO ("%p: source %p timeout", stream, source);
502 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
503 trans->rtpsource = NULL;
504 trans->timeout = TRUE;
509 handle_new_sample (GstAppSink * sink, gpointer user_data)
514 GstRTSPStream *stream;
516 sample = gst_app_sink_pull_sample (sink);
520 stream = (GstRTSPStream *) user_data;
521 buffer = gst_sample_get_buffer (sample);
523 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
524 GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data;
526 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
528 tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data);
531 tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data);
534 gst_sample_unref (sample);
539 static GstAppSinkCallbacks sink_cb = {
540 NULL, /* not interested in EOS */
541 NULL, /* not interested in preroll samples */
546 * gst_rtsp_stream_join_bin:
547 * @stream: a #GstRTSPStream
548 * @bin: a #GstBin to join
549 * @rtpbin: a rtpbin element in @bin
550 * @state: the target state of the new elements
552 * Join the #Gstbin @bin that contains the element @rtpbin.
554 * @stream will link to @rtpbin, which must be inside @bin. The elements
555 * added to @bin will be set to the state given in @state.
557 * Returns: %TRUE on success.
560 gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
561 GstElement * rtpbin, GstState state)
565 GstPad *pad, *teepad, *queuepad, *selpad;
566 GstPadLinkReturn ret;
568 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
569 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
570 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
572 if (stream->is_joined)
575 /* create a session with the same index as the stream */
578 GST_INFO ("stream %p joining bin as session %d", stream, idx);
580 if (!alloc_ports (stream))
583 /* get a pad for sending RTP */
584 name = g_strdup_printf ("send_rtp_sink_%u", idx);
585 stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
587 /* link the RTP pad to the session manager, it should not really fail unless
588 * this is not really an RTP pad */
589 ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
590 if (ret != GST_PAD_LINK_OK)
593 /* get pads from the RTP session element for sending and receiving
595 name = g_strdup_printf ("send_rtp_src_%u", idx);
596 stream->send_src[0] = gst_element_get_static_pad (rtpbin, name);
598 name = g_strdup_printf ("send_rtcp_src_%u", idx);
599 stream->send_src[1] = gst_element_get_request_pad (rtpbin, name);
601 name = g_strdup_printf ("recv_rtp_sink_%u", idx);
602 stream->recv_sink[0] = gst_element_get_request_pad (rtpbin, name);
604 name = g_strdup_printf ("recv_rtcp_sink_%u", idx);
605 stream->recv_sink[1] = gst_element_get_request_pad (rtpbin, name);
608 /* get the session */
609 g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session);
611 g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
613 g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
615 g_signal_connect (stream->session, "on-ssrc-active",
616 (GCallback) on_ssrc_active, stream);
617 g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
619 g_signal_connect (stream->session, "on-bye-timeout",
620 (GCallback) on_bye_timeout, stream);
621 g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
624 for (i = 0; i < 2; i++) {
625 /* For the sender we create this bit of pipeline for both
626 * RTP and RTCP. Sync and preroll are enabled on udpsink so
627 * we need to add a queue before appsink to make the pipeline
628 * not block. For the TCP case, we want to pump data to the
629 * client as fast as possible anyway.
631 * .--------. .-----. .---------.
632 * | rtpbin | | tee | | udpsink |
633 * | send->sink src->sink |
634 * '--------' | | '---------'
635 * | | .---------. .---------.
636 * | | | queue | | appsink |
637 * | src->sink src->sink |
638 * '-----' '---------' '---------'
640 /* make tee for RTP/RTCP */
641 stream->tee[i] = gst_element_factory_make ("tee", NULL);
642 gst_bin_add (bin, stream->tee[i]);
644 /* and link to rtpbin send pad */
645 pad = gst_element_get_static_pad (stream->tee[i], "sink");
646 gst_pad_link (stream->send_src[i], pad);
647 gst_object_unref (pad);
650 gst_bin_add (bin, stream->udpsink[i]);
652 /* link tee to udpsink */
653 teepad = gst_element_get_request_pad (stream->tee[i], "src_%u");
654 pad = gst_element_get_static_pad (stream->udpsink[i], "sink");
655 gst_pad_link (teepad, pad);
656 gst_object_unref (pad);
657 gst_object_unref (teepad);
660 stream->appqueue[i] = gst_element_factory_make ("queue", NULL);
661 gst_bin_add (bin, stream->appqueue[i]);
662 /* and link to tee */
663 teepad = gst_element_get_request_pad (stream->tee[i], "src_%u");
664 pad = gst_element_get_static_pad (stream->appqueue[i], "sink");
665 gst_pad_link (teepad, pad);
666 gst_object_unref (pad);
667 gst_object_unref (teepad);
670 stream->appsink[i] = gst_element_factory_make ("appsink", NULL);
671 g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL);
672 g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL);
673 gst_bin_add (bin, stream->appsink[i]);
674 gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
675 &sink_cb, stream, NULL);
676 /* and link to queue */
677 queuepad = gst_element_get_static_pad (stream->appqueue[i], "src");
678 pad = gst_element_get_static_pad (stream->appsink[i], "sink");
679 gst_pad_link (queuepad, pad);
680 gst_object_unref (pad);
681 gst_object_unref (queuepad);
683 /* For the receiver we create this bit of pipeline for both
684 * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
685 * and it is all funneled into the rtpbin receive pad.
687 * .--------. .--------. .--------.
688 * | udpsrc | | funnel | | rtpbin |
689 * | src->sink src->sink |
690 * '--------' | | '--------'
694 * '--------' '--------'
696 /* make funnel for the RTP/RTCP receivers */
697 stream->funnel[i] = gst_element_factory_make ("funnel", NULL);
698 gst_bin_add (bin, stream->funnel[i]);
700 pad = gst_element_get_static_pad (stream->funnel[i], "src");
701 gst_pad_link (pad, stream->recv_sink[i]);
702 gst_object_unref (pad);
705 gst_bin_add (bin, stream->udpsrc[i]);
706 /* and link to the funnel */
707 selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u");
708 pad = gst_element_get_static_pad (stream->udpsrc[i], "src");
709 gst_pad_link (pad, selpad);
710 gst_object_unref (pad);
711 gst_object_unref (selpad);
713 /* make and add appsrc */
714 stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
715 gst_bin_add (bin, stream->appsrc[i]);
716 /* and link to the funnel */
717 selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u");
718 pad = gst_element_get_static_pad (stream->appsrc[i], "src");
719 gst_pad_link (pad, selpad);
720 gst_object_unref (pad);
721 gst_object_unref (selpad);
723 /* check if we need to set to a special state */
724 if (state != GST_STATE_NULL) {
725 gst_element_set_state (stream->udpsink[i], state);
726 gst_element_set_state (stream->appsink[i], state);
727 gst_element_set_state (stream->appqueue[i], state);
728 gst_element_set_state (stream->tee[i], state);
729 gst_element_set_state (stream->funnel[i], state);
730 gst_element_set_state (stream->appsrc[i], state);
732 /* we set and keep these to playing so that they don't cause NO_PREROLL return
734 gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING);
735 gst_element_set_locked_state (stream->udpsrc[i], TRUE);
738 /* be notified of caps changes */
739 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
740 (GCallback) caps_notify, stream);
742 stream->is_joined = TRUE;
749 GST_WARNING ("failed to allocate ports %d", idx);
754 GST_WARNING ("failed to link stream %d", idx);
755 gst_object_unref (stream->send_rtp_sink);
756 stream->send_rtp_sink = NULL;
762 * gst_rtsp_stream_leave_bin:
763 * @stream: a #GstRTSPStream
765 * @rtpbin: a rtpbin #GstElement
767 * Remove the elements of @stream from @bin. @bin must be set
768 * to the NULL state before calling this.
770 * Return: %TRUE on success.
773 gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
778 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
779 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
780 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
782 if (!stream->is_joined)
785 /* all transports must be removed by now */
786 g_return_val_if_fail (stream->transports == NULL, FALSE);
788 GST_INFO ("stream %p leaving bin", stream);
790 gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
791 g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
792 gst_element_release_request_pad (rtpbin, stream->send_rtp_sink);
793 gst_object_unref (stream->send_rtp_sink);
794 stream->send_rtp_sink = NULL;
796 for (i = 0; i < 2; i++) {
797 /* and set udpsrc to NULL now before removing */
798 gst_element_set_locked_state (stream->udpsrc[i], FALSE);
799 gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
801 /* removing them should also nicely release the request
802 * pads when they finalize */
803 gst_bin_remove (bin, stream->udpsrc[i]);
804 gst_bin_remove (bin, stream->udpsink[i]);
805 gst_bin_remove (bin, stream->appsrc[i]);
806 gst_bin_remove (bin, stream->appsink[i]);
807 gst_bin_remove (bin, stream->appqueue[i]);
808 gst_bin_remove (bin, stream->tee[i]);
809 gst_bin_remove (bin, stream->funnel[i]);
811 gst_element_release_request_pad (rtpbin, stream->recv_sink[i]);
812 gst_object_unref (stream->recv_sink[i]);
813 stream->recv_sink[i] = NULL;
815 stream->udpsrc[i] = NULL;
816 stream->udpsink[i] = NULL;
817 stream->appsrc[i] = NULL;
818 stream->appsink[i] = NULL;
819 stream->appqueue[i] = NULL;
820 stream->tee[i] = NULL;
821 stream->funnel[i] = NULL;
823 gst_object_unref (stream->send_src[0]);
824 stream->send_src[0] = NULL;
826 gst_element_release_request_pad (rtpbin, stream->send_src[1]);
827 gst_object_unref (stream->send_src[1]);
828 stream->send_src[1] = NULL;
830 g_object_unref (stream->session);
832 gst_caps_unref (stream->caps);
834 stream->is_joined = FALSE;
840 * gst_rtsp_stream_get_rtpinfo:
841 * @stream: a #GstRTSPStream
842 * @rtptime: result RTP timestamp
843 * @seq: result RTP seqnum
845 * Retrieve the current rtptime and seq. This is used to
846 * construct a RTPInfo reply header.
848 * Returns: %TRUE when rtptime and seq could be determined.
851 gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
852 guint * rtptime, guint * seq)
854 GObjectClass *payobjclass;
856 payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
858 if (!g_object_class_find_property (payobjclass, "seqnum") ||
859 !g_object_class_find_property (payobjclass, "timestamp"))
862 g_object_get (stream->payloader, "seqnum", seq, "timestamp", rtptime, NULL);
868 * gst_rtsp_stream_recv_rtp:
869 * @stream: a #GstRTSPStream
870 * @buffer: (transfer full): a #GstBuffer
872 * Handle an RTP buffer for the stream. This method is usually called when a
873 * message has been received from a client using the TCP transport.
875 * This function takes ownership of @buffer.
877 * Returns: a GstFlowReturn.
880 gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer)
884 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR);
885 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
886 g_return_val_if_fail (stream->is_joined, FALSE);
888 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer);
894 * gst_rtsp_stream_recv_rtcp:
895 * @stream: a #GstRTSPStream
896 * @buffer: (transfer full): a #GstBuffer
898 * Handle an RTCP buffer for the stream. This method is usually called when a
899 * message has been received from a client using the TCP transport.
901 * This function takes ownership of @buffer.
903 * Returns: a GstFlowReturn.
906 gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer)
910 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR);
911 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
912 g_return_val_if_fail (stream->is_joined, FALSE);
914 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer);
920 update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
923 GstRTSPTransport *tr;
928 tr = trans->transport;
930 switch (tr->lower_transport) {
931 case GST_RTSP_LOWER_TRANS_UDP:
932 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
938 dest = tr->destination;
939 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
944 min = tr->client_port.min;
945 max = tr->client_port.max;
948 if (add && !trans->active) {
949 GST_INFO ("adding %s:%d-%d", dest, min, max);
950 g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
951 g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
953 GST_INFO ("setting ttl-mc %d", ttl);
954 g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL);
955 g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL);
957 stream->transports = g_list_prepend (stream->transports, trans);
958 trans->active = TRUE;
960 } else if (trans->active) {
961 GST_INFO ("removing %s:%d-%d", dest, min, max);
962 g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
963 g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
964 stream->transports = g_list_remove (stream->transports, trans);
965 trans->active = FALSE;
970 case GST_RTSP_LOWER_TRANS_TCP:
971 if (add && !trans->active) {
972 GST_INFO ("adding TCP %s", tr->destination);
973 stream->transports = g_list_prepend (stream->transports, trans);
974 trans->active = TRUE;
976 } else if (trans->active) {
977 GST_INFO ("removing TCP %s", tr->destination);
978 stream->transports = g_list_remove (stream->transports, trans);
979 trans->active = FALSE;
984 GST_INFO ("Unknown transport %d", tr->lower_transport);
992 * gst_rtsp_stream_add_transport:
993 * @stream: a #GstRTSPStream
994 * @trans: a #GstRTSPStreamTransport
996 * Add the transport in @trans to @stream. The media of @stream will
997 * then also be send to the values configured in @trans.
999 * @stream must be joined to a bin.
1001 * @trans must contain a valid #GstRTSPTransport.
1003 * Returns: %TRUE if @trans was added
1006 gst_rtsp_stream_add_transport (GstRTSPStream * stream,
1007 GstRTSPStreamTransport * trans)
1009 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
1010 g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
1011 g_return_val_if_fail (stream->is_joined, FALSE);
1012 g_return_val_if_fail (trans->transport != NULL, FALSE);
1014 return update_transport (stream, trans, TRUE);
1018 * gst_rtsp_stream_remove_transport:
1019 * @stream: a #GstRTSPStream
1020 * @trans: a #GstRTSPStreamTransport
1022 * Remove the transport in @trans from @stream. The media of @stream will
1023 * not be sent to the values configured in @trans.
1025 * @stream must be joined to a bin.
1027 * @trans must contain a valid #GstRTSPTransport.
1029 * Returns: %TRUE if @trans was removed
1032 gst_rtsp_stream_remove_transport (GstRTSPStream * stream,
1033 GstRTSPStreamTransport * trans)
1035 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
1036 g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
1037 g_return_val_if_fail (stream->is_joined, FALSE);
1038 g_return_val_if_fail (trans->transport != NULL, FALSE);
1040 return update_transport (stream, trans, FALSE);