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.
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_list_free (stream->transports);
79 G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj);
83 * gst_rtsp_stream_new:
86 * @payloader: a #GstElement
88 * Create a new media stream with index @idx that handles RTP data on
89 * @srcpad and has a payloader element @payloader.
91 * Returns: a new #GstRTSPStream
94 gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad)
96 GstRTSPStream *stream;
98 g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
99 g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
100 g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
102 stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL);
104 stream->payloader = gst_object_ref (payloader);
105 stream->srcpad = gst_object_ref (srcpad);
111 * gst_rtsp_stream_set_mtu:
112 * @stream: a #GstRTSPStream
115 * Configure the mtu in the payloader of @stream to @mtu.
118 gst_rtsp_stream_set_mtu (GstRTSPStream * stream, guint mtu)
120 g_return_if_fail (GST_IS_RTSP_STREAM (stream));
122 g_object_set (G_OBJECT (stream->payloader), "mtu", mtu, NULL);
126 * gst_rtsp_stream_get_mtu:
127 * @stream: a #GstRTSPStream
129 * Get the configured MTU in the payloader of @stream.
131 * Returns: the MTU of the payloader.
134 gst_rtsp_stream_get_mtu (GstRTSPStream * stream)
138 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0);
140 g_object_get (G_OBJECT (stream->payloader), "mtu", &mtu, NULL);
146 alloc_ports (GstRTSPStream * stream)
148 GstStateChangeReturn ret;
149 GstElement *udpsrc0, *udpsrc1;
150 GstElement *udpsink0, *udpsink1;
151 gint tmp_rtp, tmp_rtcp;
153 gint rtpport, rtcpport;
157 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
165 /* Start with random port */
169 host = "udp://[::0]";
171 host = "udp://0.0.0.0";
173 /* try to allocate 2 UDP ports, the RTP port should be an even
174 * number and the RTCP port should be the next (uneven) port */
176 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
178 goto no_udp_protocol;
179 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
181 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
182 if (ret == GST_STATE_CHANGE_FAILURE) {
188 gst_element_set_state (udpsrc0, GST_STATE_NULL);
189 gst_object_unref (udpsrc0);
193 goto no_udp_protocol;
196 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
198 /* check if port is even */
199 if ((tmp_rtp & 1) != 0) {
200 /* port not even, close and allocate another */
204 gst_element_set_state (udpsrc0, GST_STATE_NULL);
205 gst_object_unref (udpsrc0);
211 /* allocate port+1 for RTCP now */
212 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
214 goto no_udp_rtcp_protocol;
217 tmp_rtcp = tmp_rtp + 1;
218 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
220 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
221 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
222 if (ret == GST_STATE_CHANGE_FAILURE) {
227 gst_element_set_state (udpsrc0, GST_STATE_NULL);
228 gst_object_unref (udpsrc0);
230 gst_element_set_state (udpsrc1, GST_STATE_NULL);
231 gst_object_unref (udpsrc1);
236 /* all fine, do port check */
237 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
238 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
240 /* this should not happen... */
241 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
244 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
246 goto no_udp_protocol;
248 g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL);
249 g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL);
250 g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL);
252 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
254 goto no_udp_protocol;
256 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
257 "send-duplicates")) {
258 g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
259 g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
262 ("old multiudpsink version found without send-duplicates property");
265 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
267 g_object_set (G_OBJECT (udpsink0), "buffer-size", stream->buffer_size,
270 GST_WARNING ("multiudpsink version found without buffer-size property");
273 g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL);
274 g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL);
275 g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL);
276 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
277 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
278 g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
279 g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL);
280 g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL);
281 g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL);
283 /* we keep these elements, we will further configure them when the
284 * client told us to really use the UDP ports. */
285 stream->udpsrc[0] = udpsrc0;
286 stream->udpsrc[1] = udpsrc1;
287 stream->udpsink[0] = udpsink0;
288 stream->udpsink[1] = udpsink1;
289 stream->server_port.min = rtpport;
290 stream->server_port.max = rtcpport;
303 no_udp_rtcp_protocol:
314 gst_element_set_state (udpsrc0, GST_STATE_NULL);
315 gst_object_unref (udpsrc0);
318 gst_element_set_state (udpsrc1, GST_STATE_NULL);
319 gst_object_unref (udpsrc1);
322 gst_element_set_state (udpsink0, GST_STATE_NULL);
323 gst_object_unref (udpsink0);
326 gst_element_set_state (udpsink1, GST_STATE_NULL);
327 gst_object_unref (udpsink1);
333 /* executed from streaming thread */
335 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream)
337 GstCaps *newcaps, *oldcaps;
339 newcaps = gst_pad_get_current_caps (pad);
341 oldcaps = stream->caps;
342 stream->caps = newcaps;
345 gst_caps_unref (oldcaps);
347 GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps,
352 dump_structure (const GstStructure * s)
356 sstr = gst_structure_to_string (s);
357 GST_INFO ("structure: %s", sstr);
361 static GstRTSPStreamTransport *
362 find_transport (GstRTSPStream * stream, const gchar * rtcp_from)
365 GstRTSPStreamTransport *result = NULL;
370 if (rtcp_from == NULL)
373 tmp = g_strrstr (rtcp_from, ":");
377 port = atoi (tmp + 1);
378 dest = g_strndup (rtcp_from, tmp - rtcp_from);
380 GST_INFO ("finding %s:%d in %d transports", dest, port,
381 g_list_length (stream->transports));
383 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
384 GstRTSPStreamTransport *trans = walk->data;
387 min = trans->transport->client_port.min;
388 max = trans->transport->client_port.max;
390 if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
401 static GstRTSPStreamTransport *
402 check_transport (GObject * source, GstRTSPStream * stream)
405 GstRTSPStreamTransport *trans;
407 /* see if we have a stream to match with the origin of the RTCP packet */
408 trans = g_object_get_qdata (source, ssrc_stream_map_key);
410 g_object_get (source, "stats", &stats, NULL);
412 const gchar *rtcp_from;
414 dump_structure (stats);
416 rtcp_from = gst_structure_get_string (stats, "rtcp-from");
417 if ((trans = find_transport (stream, rtcp_from))) {
418 GST_INFO ("%p: found transport %p for source %p", stream, trans,
421 /* keep ref to the source */
422 trans->rtpsource = source;
424 g_object_set_qdata (source, ssrc_stream_map_key, trans);
426 gst_structure_free (stats);
435 on_new_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
437 GstRTSPStreamTransport *trans;
439 GST_INFO ("%p: new source %p", stream, source);
441 trans = check_transport (source, stream);
444 GST_INFO ("%p: source %p for transport %p", stream, source, trans);
448 on_ssrc_sdes (GObject * session, GObject * source, GstRTSPStream * stream)
450 GST_INFO ("%p: new SDES %p", stream, source);
454 on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream)
456 GstRTSPStreamTransport *trans;
458 trans = check_transport (source, stream);
461 GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
463 if (trans && trans->keep_alive)
464 trans->keep_alive (trans->ka_user_data);
469 g_object_get (source, "stats", &stats, NULL);
471 dump_structure (stats);
472 gst_structure_free (stats);
479 on_bye_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
481 GST_INFO ("%p: source %p bye", stream, source);
485 on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
487 GstRTSPStreamTransport *trans;
489 GST_INFO ("%p: source %p bye timeout", stream, source);
491 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
492 trans->rtpsource = NULL;
493 trans->timeout = TRUE;
498 on_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
500 GstRTSPStreamTransport *trans;
502 GST_INFO ("%p: source %p timeout", stream, source);
504 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
505 trans->rtpsource = NULL;
506 trans->timeout = TRUE;
511 handle_new_sample (GstAppSink * sink, gpointer user_data)
516 GstRTSPStream *stream;
518 sample = gst_app_sink_pull_sample (sink);
522 stream = (GstRTSPStream *) user_data;
523 buffer = gst_sample_get_buffer (sample);
525 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
526 GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data;
528 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
530 tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data);
533 tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data);
536 gst_sample_unref (sample);
541 static GstAppSinkCallbacks sink_cb = {
542 NULL, /* not interested in EOS */
543 NULL, /* not interested in preroll samples */
548 * gst_rtsp_stream_join_bin:
549 * @stream: a #GstRTSPStream
550 * @bin: a #GstBin to join
551 * @rtpbin: a rtpbin element in @bin
552 * @state: the target state of the new elements
554 * Join the #Gstbin @bin that contains the element @rtpbin.
556 * @stream will link to @rtpbin, which must be inside @bin. The elements
557 * added to @bin will be set to the state given in @state.
559 * Returns: %TRUE on success.
562 gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
563 GstElement * rtpbin, GstState state)
567 GstPad *pad, *teepad, *queuepad, *selpad;
568 GstPadLinkReturn ret;
570 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
571 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
572 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
574 if (stream->is_joined)
577 /* create a session with the same index as the stream */
580 GST_INFO ("stream %p joining bin as session %d", stream, idx);
582 if (!alloc_ports (stream))
585 /* get a pad for sending RTP */
586 name = g_strdup_printf ("send_rtp_sink_%u", idx);
587 stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
589 /* link the RTP pad to the session manager, it should not really fail unless
590 * this is not really an RTP pad */
591 ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
592 if (ret != GST_PAD_LINK_OK)
595 /* get pads from the RTP session element for sending and receiving
597 name = g_strdup_printf ("send_rtp_src_%u", idx);
598 stream->send_src[0] = gst_element_get_static_pad (rtpbin, name);
600 name = g_strdup_printf ("send_rtcp_src_%u", idx);
601 stream->send_src[1] = gst_element_get_request_pad (rtpbin, name);
603 name = g_strdup_printf ("recv_rtp_sink_%u", idx);
604 stream->recv_sink[0] = gst_element_get_request_pad (rtpbin, name);
606 name = g_strdup_printf ("recv_rtcp_sink_%u", idx);
607 stream->recv_sink[1] = gst_element_get_request_pad (rtpbin, name);
610 /* get the session */
611 g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session);
613 g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
615 g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
617 g_signal_connect (stream->session, "on-ssrc-active",
618 (GCallback) on_ssrc_active, stream);
619 g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
621 g_signal_connect (stream->session, "on-bye-timeout",
622 (GCallback) on_bye_timeout, stream);
623 g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
626 for (i = 0; i < 2; i++) {
627 /* For the sender we create this bit of pipeline for both
628 * RTP and RTCP. Sync and preroll are enabled on udpsink so
629 * we need to add a queue before appsink to make the pipeline
630 * not block. For the TCP case, we want to pump data to the
631 * client as fast as possible anyway.
633 * .--------. .-----. .---------.
634 * | rtpbin | | tee | | udpsink |
635 * | send->sink src->sink |
636 * '--------' | | '---------'
637 * | | .---------. .---------.
638 * | | | queue | | appsink |
639 * | src->sink src->sink |
640 * '-----' '---------' '---------'
642 /* make tee for RTP/RTCP */
643 stream->tee[i] = gst_element_factory_make ("tee", NULL);
644 gst_bin_add (bin, stream->tee[i]);
646 /* and link to rtpbin send pad */
647 pad = gst_element_get_static_pad (stream->tee[i], "sink");
648 gst_pad_link (stream->send_src[i], pad);
649 gst_object_unref (pad);
652 gst_bin_add (bin, stream->udpsink[i]);
654 /* link tee to udpsink */
655 teepad = gst_element_get_request_pad (stream->tee[i], "src_%u");
656 pad = gst_element_get_static_pad (stream->udpsink[i], "sink");
657 gst_pad_link (teepad, pad);
658 gst_object_unref (pad);
659 gst_object_unref (teepad);
662 stream->appqueue[i] = gst_element_factory_make ("queue", NULL);
663 gst_bin_add (bin, stream->appqueue[i]);
664 /* and link to tee */
665 teepad = gst_element_get_request_pad (stream->tee[i], "src_%u");
666 pad = gst_element_get_static_pad (stream->appqueue[i], "sink");
667 gst_pad_link (teepad, pad);
668 gst_object_unref (pad);
669 gst_object_unref (teepad);
672 stream->appsink[i] = gst_element_factory_make ("appsink", NULL);
673 g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL);
674 g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL);
675 gst_bin_add (bin, stream->appsink[i]);
676 gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
677 &sink_cb, stream, NULL);
678 /* and link to queue */
679 queuepad = gst_element_get_static_pad (stream->appqueue[i], "src");
680 pad = gst_element_get_static_pad (stream->appsink[i], "sink");
681 gst_pad_link (queuepad, pad);
682 gst_object_unref (pad);
683 gst_object_unref (queuepad);
685 /* For the receiver we create this bit of pipeline for both
686 * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
687 * and it is all funneled into the rtpbin receive pad.
689 * .--------. .--------. .--------.
690 * | udpsrc | | funnel | | rtpbin |
691 * | src->sink src->sink |
692 * '--------' | | '--------'
696 * '--------' '--------'
698 /* make funnel for the RTP/RTCP receivers */
699 stream->funnel[i] = gst_element_factory_make ("funnel", NULL);
700 gst_bin_add (bin, stream->funnel[i]);
702 pad = gst_element_get_static_pad (stream->funnel[i], "src");
703 gst_pad_link (pad, stream->recv_sink[i]);
704 gst_object_unref (pad);
707 gst_bin_add (bin, stream->udpsrc[i]);
708 /* and link to the funnel */
709 selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u");
710 pad = gst_element_get_static_pad (stream->udpsrc[i], "src");
711 gst_pad_link (pad, selpad);
712 gst_object_unref (pad);
713 gst_object_unref (selpad);
715 /* make and add appsrc */
716 stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
717 gst_bin_add (bin, stream->appsrc[i]);
718 /* and link to the funnel */
719 selpad = gst_element_get_request_pad (stream->funnel[i], "sink_%u");
720 pad = gst_element_get_static_pad (stream->appsrc[i], "src");
721 gst_pad_link (pad, selpad);
722 gst_object_unref (pad);
723 gst_object_unref (selpad);
725 /* check if we need to set to a special state */
726 if (state != GST_STATE_NULL) {
727 gst_element_set_state (stream->udpsink[i], state);
728 gst_element_set_state (stream->appsink[i], state);
729 gst_element_set_state (stream->appqueue[i], state);
730 gst_element_set_state (stream->tee[i], state);
731 gst_element_set_state (stream->funnel[i], state);
732 gst_element_set_state (stream->appsrc[i], state);
734 /* we set and keep these to playing so that they don't cause NO_PREROLL return
736 gst_element_set_state (stream->udpsrc[i], GST_STATE_PLAYING);
737 gst_element_set_locked_state (stream->udpsrc[i], TRUE);
740 /* be notified of caps changes */
741 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
742 (GCallback) caps_notify, stream);
744 stream->is_joined = TRUE;
751 GST_WARNING ("failed to allocate ports %d", idx);
756 GST_WARNING ("failed to link stream %d", idx);
757 gst_object_unref (stream->send_rtp_sink);
758 stream->send_rtp_sink = NULL;
764 * gst_rtsp_stream_leave_bin:
765 * @stream: a #GstRTSPStream
767 * @rtpbin: a rtpbin #GstElement
769 * Remove the elements of @stream from @bin. @bin must be set
770 * to the NULL state before calling this.
772 * Return: %TRUE on success.
775 gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
780 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
781 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
782 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
784 if (!stream->is_joined)
787 /* all transports must be removed by now */
788 g_return_val_if_fail (stream->transports == NULL, FALSE);
790 GST_INFO ("stream %p leaving bin", stream);
792 gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
793 g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
794 gst_element_release_request_pad (rtpbin, stream->send_rtp_sink);
795 gst_object_unref (stream->send_rtp_sink);
796 stream->send_rtp_sink = NULL;
798 for (i = 0; i < 2; i++) {
799 /* and set udpsrc to NULL now before removing */
800 gst_element_set_locked_state (stream->udpsrc[i], FALSE);
801 gst_element_set_state (stream->udpsrc[i], GST_STATE_NULL);
803 /* removing them should also nicely release the request
804 * pads when they finalize */
805 gst_bin_remove (bin, stream->udpsrc[i]);
806 gst_bin_remove (bin, stream->udpsink[i]);
807 gst_bin_remove (bin, stream->appsrc[i]);
808 gst_bin_remove (bin, stream->appsink[i]);
809 gst_bin_remove (bin, stream->appqueue[i]);
810 gst_bin_remove (bin, stream->tee[i]);
811 gst_bin_remove (bin, stream->funnel[i]);
813 gst_element_release_request_pad (rtpbin, stream->recv_sink[i]);
814 gst_object_unref (stream->recv_sink[i]);
815 stream->recv_sink[i] = NULL;
817 stream->udpsrc[i] = NULL;
818 stream->udpsink[i] = NULL;
819 stream->appsrc[i] = NULL;
820 stream->appsink[i] = NULL;
821 stream->appqueue[i] = NULL;
822 stream->tee[i] = NULL;
823 stream->funnel[i] = NULL;
825 gst_object_unref (stream->send_src[0]);
826 stream->send_src[0] = NULL;
828 gst_element_release_request_pad (rtpbin, stream->send_src[1]);
829 gst_object_unref (stream->send_src[1]);
830 stream->send_src[1] = NULL;
832 g_object_unref (stream->session);
834 gst_caps_unref (stream->caps);
836 stream->is_joined = FALSE;
842 * gst_rtsp_stream_get_rtpinfo:
843 * @stream: a #GstRTSPStream
844 * @rtptime: result RTP timestamp
845 * @seq: result RTP seqnum
847 * Retrieve the current rtptime and seq. This is used to
848 * construct a RTPInfo reply header.
850 * Returns: %TRUE when rtptime and seq could be determined.
853 gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
854 guint * rtptime, guint * seq)
856 GObjectClass *payobjclass;
858 payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
860 if (!g_object_class_find_property (payobjclass, "seqnum") ||
861 !g_object_class_find_property (payobjclass, "timestamp"))
864 g_object_get (stream->payloader, "seqnum", seq, "timestamp", rtptime, NULL);
870 * gst_rtsp_stream_recv_rtp:
871 * @stream: a #GstRTSPStream
872 * @buffer: (transfer full): a #GstBuffer
874 * Handle an RTP buffer for the stream. This method is usually called when a
875 * message has been received from a client using the TCP transport.
877 * This function takes ownership of @buffer.
879 * Returns: a GstFlowReturn.
882 gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer)
886 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR);
887 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
888 g_return_val_if_fail (stream->is_joined, FALSE);
890 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer);
896 * gst_rtsp_stream_recv_rtcp:
897 * @stream: a #GstRTSPStream
898 * @buffer: (transfer full): a #GstBuffer
900 * Handle an RTCP buffer for the stream. This method is usually called when a
901 * message has been received from a client using the TCP transport.
903 * This function takes ownership of @buffer.
905 * Returns: a GstFlowReturn.
908 gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer)
912 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_FLOW_ERROR);
913 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
914 g_return_val_if_fail (stream->is_joined, FALSE);
916 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer);
922 update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
925 GstRTSPTransport *tr;
930 tr = trans->transport;
932 switch (tr->lower_transport) {
933 case GST_RTSP_LOWER_TRANS_UDP:
934 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
940 dest = tr->destination;
941 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
946 min = tr->client_port.min;
947 max = tr->client_port.max;
950 if (add && !trans->active) {
951 GST_INFO ("adding %s:%d-%d", dest, min, max);
952 g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
953 g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
955 GST_INFO ("setting ttl-mc %d", ttl);
956 g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL);
957 g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL);
959 stream->transports = g_list_prepend (stream->transports, trans);
960 trans->active = TRUE;
962 } else if (trans->active) {
963 GST_INFO ("removing %s:%d-%d", dest, min, max);
964 g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
965 g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
966 stream->transports = g_list_remove (stream->transports, trans);
967 trans->active = FALSE;
972 case GST_RTSP_LOWER_TRANS_TCP:
973 if (add && !trans->active) {
974 GST_INFO ("adding TCP %s", tr->destination);
975 stream->transports = g_list_prepend (stream->transports, trans);
976 trans->active = TRUE;
978 } else if (trans->active) {
979 GST_INFO ("removing TCP %s", tr->destination);
980 stream->transports = g_list_remove (stream->transports, trans);
981 trans->active = FALSE;
986 GST_INFO ("Unknown transport %d", tr->lower_transport);
994 * gst_rtsp_stream_add_transport:
995 * @stream: a #GstRTSPStream
996 * @trans: a #GstRTSPStreamTransport
998 * Add the transport in @trans to @stream. The media of @stream will
999 * then also be send to the values configured in @trans.
1001 * @stream must be joined to a bin.
1003 * @trans must contain a valid #GstRTSPTransport.
1005 * Returns: %TRUE if @trans was added
1008 gst_rtsp_stream_add_transport (GstRTSPStream * stream,
1009 GstRTSPStreamTransport * trans)
1011 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
1012 g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
1013 g_return_val_if_fail (stream->is_joined, FALSE);
1014 g_return_val_if_fail (trans->transport != NULL, FALSE);
1016 return update_transport (stream, trans, TRUE);
1020 * gst_rtsp_stream_remove_transport:
1021 * @stream: a #GstRTSPStream
1022 * @trans: a #GstRTSPStreamTransport
1024 * Remove the transport in @trans from @stream. The media of @stream will
1025 * not be sent to the values configured in @trans.
1027 * @stream must be joined to a bin.
1029 * @trans must contain a valid #GstRTSPTransport.
1031 * Returns: %TRUE if @trans was removed
1034 gst_rtsp_stream_remove_transport (GstRTSPStream * stream,
1035 GstRTSPStreamTransport * trans)
1037 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
1038 g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
1039 g_return_val_if_fail (stream->is_joined, FALSE);
1040 g_return_val_if_fail (trans->transport != NULL, FALSE);
1042 return update_transport (stream, trans, FALSE);