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 g_assert (!stream->is_joined);
73 gst_object_unref (stream->payloader);
74 gst_object_unref (stream->srcpad);
77 g_object_unref (stream->session);
80 gst_caps_unref (stream->caps);
82 if (stream->send_rtp_sink)
83 gst_object_unref (stream->send_rtp_sink);
84 if (stream->send_rtp_src)
85 gst_object_unref (stream->send_rtp_src);
86 if (stream->send_rtcp_src)
87 gst_object_unref (stream->send_rtcp_src);
88 if (stream->recv_rtcp_sink)
89 gst_object_unref (stream->recv_rtcp_sink);
90 if (stream->recv_rtp_sink)
91 gst_object_unref (stream->recv_rtp_sink);
93 g_list_free (stream->transports);
95 G_OBJECT_CLASS (gst_rtsp_stream_parent_class)->finalize (obj);
99 * gst_rtsp_stream_new:
102 * @payloader: a #GstElement
104 * Create a new media stream with index @idx that handles RTP data on
105 * @srcpad and has a payloader element @payloader.
107 * Returns: a new #GstRTSPStream
110 gst_rtsp_stream_new (guint idx, GstElement * payloader, GstPad * srcpad)
112 GstRTSPStream *stream;
114 g_return_val_if_fail (GST_IS_ELEMENT (payloader), NULL);
115 g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
116 g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
118 stream = g_object_new (GST_TYPE_RTSP_STREAM, NULL);
120 stream->payloader = gst_object_ref (payloader);
121 stream->srcpad = gst_object_ref (srcpad);
127 alloc_ports (GstRTSPStream * stream)
129 GstStateChangeReturn ret;
130 GstElement *udpsrc0, *udpsrc1;
131 GstElement *udpsink0, *udpsink1;
132 gint tmp_rtp, tmp_rtcp;
134 gint rtpport, rtcpport;
138 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
146 /* Start with random port */
150 host = "udp://[::0]";
152 host = "udp://0.0.0.0";
154 /* try to allocate 2 UDP ports, the RTP port should be an even
155 * number and the RTCP port should be the next (uneven) port */
157 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
159 goto no_udp_protocol;
160 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
162 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
163 if (ret == GST_STATE_CHANGE_FAILURE) {
169 gst_element_set_state (udpsrc0, GST_STATE_NULL);
170 gst_object_unref (udpsrc0);
174 goto no_udp_protocol;
177 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
179 /* check if port is even */
180 if ((tmp_rtp & 1) != 0) {
181 /* port not even, close and allocate another */
185 gst_element_set_state (udpsrc0, GST_STATE_NULL);
186 gst_object_unref (udpsrc0);
192 /* allocate port+1 for RTCP now */
193 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
195 goto no_udp_rtcp_protocol;
198 tmp_rtcp = tmp_rtp + 1;
199 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
201 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
202 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
203 if (ret == GST_STATE_CHANGE_FAILURE) {
208 gst_element_set_state (udpsrc0, GST_STATE_NULL);
209 gst_object_unref (udpsrc0);
211 gst_element_set_state (udpsrc1, GST_STATE_NULL);
212 gst_object_unref (udpsrc1);
217 /* all fine, do port check */
218 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
219 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
221 /* this should not happen... */
222 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
225 udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
227 goto no_udp_protocol;
229 g_object_get (G_OBJECT (udpsrc0), "socket", &socket, NULL);
230 g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL);
231 g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL);
233 udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
235 goto no_udp_protocol;
237 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
238 "send-duplicates")) {
239 g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
240 g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
243 ("old multiudpsink version found without send-duplicates property");
246 if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
248 g_object_set (G_OBJECT (udpsink0), "buffer-size", stream->buffer_size,
251 GST_WARNING ("multiudpsink version found without buffer-size property");
254 g_object_get (G_OBJECT (udpsrc1), "socket", &socket, NULL);
255 g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL);
256 g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL);
257 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
258 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
259 g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
260 g_object_set (G_OBJECT (udpsink0), "loop", FALSE, NULL);
261 g_object_set (G_OBJECT (udpsink1), "auto-multicast", FALSE, NULL);
262 g_object_set (G_OBJECT (udpsink1), "loop", FALSE, NULL);
264 /* we keep these elements, we will further configure them when the
265 * client told us to really use the UDP ports. */
266 stream->udpsrc[0] = udpsrc0;
267 stream->udpsrc[1] = udpsrc1;
268 stream->udpsink[0] = udpsink0;
269 stream->udpsink[1] = udpsink1;
270 stream->server_port.min = rtpport;
271 stream->server_port.max = rtcpport;
284 no_udp_rtcp_protocol:
295 gst_element_set_state (udpsrc0, GST_STATE_NULL);
296 gst_object_unref (udpsrc0);
299 gst_element_set_state (udpsrc1, GST_STATE_NULL);
300 gst_object_unref (udpsrc1);
303 gst_element_set_state (udpsink0, GST_STATE_NULL);
304 gst_object_unref (udpsink0);
307 gst_element_set_state (udpsink1, GST_STATE_NULL);
308 gst_object_unref (udpsink1);
314 /* executed from streaming thread */
316 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream)
318 GstCaps *newcaps, *oldcaps;
320 newcaps = gst_pad_get_current_caps (pad);
322 oldcaps = stream->caps;
323 stream->caps = newcaps;
326 gst_caps_unref (oldcaps);
328 GST_INFO ("stream %p received caps %p, %" GST_PTR_FORMAT, stream, newcaps,
333 dump_structure (const GstStructure * s)
337 sstr = gst_structure_to_string (s);
338 GST_INFO ("structure: %s", sstr);
342 static GstRTSPStreamTransport *
343 find_transport (GstRTSPStream * stream, const gchar * rtcp_from)
346 GstRTSPStreamTransport *result = NULL;
351 if (rtcp_from == NULL)
354 tmp = g_strrstr (rtcp_from, ":");
358 port = atoi (tmp + 1);
359 dest = g_strndup (rtcp_from, tmp - rtcp_from);
361 GST_INFO ("finding %s:%d in %d transports", dest, port,
362 g_list_length (stream->transports));
364 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
365 GstRTSPStreamTransport *trans = walk->data;
368 min = trans->transport->client_port.min;
369 max = trans->transport->client_port.max;
371 if ((strcmp (trans->transport->destination, dest) == 0) && (min == port
382 static GstRTSPStreamTransport *
383 check_transport (GObject * source, GstRTSPStream * stream)
386 GstRTSPStreamTransport *trans;
388 /* see if we have a stream to match with the origin of the RTCP packet */
389 trans = g_object_get_qdata (source, ssrc_stream_map_key);
391 g_object_get (source, "stats", &stats, NULL);
393 const gchar *rtcp_from;
395 dump_structure (stats);
397 rtcp_from = gst_structure_get_string (stats, "rtcp-from");
398 if ((trans = find_transport (stream, rtcp_from))) {
399 GST_INFO ("%p: found transport %p for source %p", stream, trans,
402 /* keep ref to the source */
403 trans->rtpsource = source;
405 g_object_set_qdata (source, ssrc_stream_map_key, trans);
407 gst_structure_free (stats);
416 on_new_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
418 GstRTSPStreamTransport *trans;
420 GST_INFO ("%p: new source %p", stream, source);
422 trans = check_transport (source, stream);
425 GST_INFO ("%p: source %p for transport %p", stream, source, trans);
429 on_ssrc_sdes (GObject * session, GObject * source, GstRTSPStream * stream)
431 GST_INFO ("%p: new SDES %p", stream, source);
435 on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream)
437 GstRTSPStreamTransport *trans;
439 trans = check_transport (source, stream);
442 GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
444 if (trans && trans->keep_alive)
445 trans->keep_alive (trans->ka_user_data);
450 g_object_get (source, "stats", &stats, NULL);
452 dump_structure (stats);
453 gst_structure_free (stats);
460 on_bye_ssrc (GObject * session, GObject * source, GstRTSPStream * stream)
462 GST_INFO ("%p: source %p bye", stream, source);
466 on_bye_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
468 GstRTSPStreamTransport *trans;
470 GST_INFO ("%p: source %p bye timeout", stream, source);
472 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
473 trans->rtpsource = NULL;
474 trans->timeout = TRUE;
479 on_timeout (GObject * session, GObject * source, GstRTSPStream * stream)
481 GstRTSPStreamTransport *trans;
483 GST_INFO ("%p: source %p timeout", stream, source);
485 if ((trans = g_object_get_qdata (source, ssrc_stream_map_key))) {
486 trans->rtpsource = NULL;
487 trans->timeout = TRUE;
492 handle_new_sample (GstAppSink * sink, gpointer user_data)
497 GstRTSPStream *stream;
499 sample = gst_app_sink_pull_sample (sink);
503 stream = (GstRTSPStream *) user_data;
504 buffer = gst_sample_get_buffer (sample);
506 for (walk = stream->transports; walk; walk = g_list_next (walk)) {
507 GstRTSPStreamTransport *tr = (GstRTSPStreamTransport *) walk->data;
509 if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
511 tr->send_rtp (buffer, tr->transport->interleaved.min, tr->user_data);
514 tr->send_rtcp (buffer, tr->transport->interleaved.max, tr->user_data);
517 gst_sample_unref (sample);
522 static GstAppSinkCallbacks sink_cb = {
523 NULL, /* not interested in EOS */
524 NULL, /* not interested in preroll samples */
529 * gst_rtsp_stream_join_bin:
530 * @stream: a #GstRTSPStream
531 * @bin: a #GstBin to join
532 * @rtpbin: a rtpbin element in @bin
534 * Join the #Gstbin @bin that contains the element @rtpbin.
536 * @stream will link to @rtpbin, which must be inside @bin.
538 * Returns: %TRUE on success.
541 gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
546 GstPad *pad, *teepad, *queuepad, *selpad;
547 GstPadLinkReturn ret;
549 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
550 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
551 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
555 if (stream->is_joined)
558 GST_INFO ("stream %p joining bin", stream);
560 if (!alloc_ports (stream))
563 /* add the ports to the pipeline */
564 for (i = 0; i < 2; i++) {
565 gst_bin_add (bin, stream->udpsink[i]);
566 gst_bin_add (bin, stream->udpsrc[i]);
569 /* create elements for the TCP transfer */
570 for (i = 0; i < 2; i++) {
571 stream->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
572 stream->appqueue[i] = gst_element_factory_make ("queue", NULL);
573 stream->appsink[i] = gst_element_factory_make ("appsink", NULL);
574 g_object_set (stream->appsink[i], "async", FALSE, "sync", FALSE, NULL);
575 g_object_set (stream->appsink[i], "emit-signals", FALSE, NULL);
576 gst_bin_add (bin, stream->appqueue[i]);
577 gst_bin_add (bin, stream->appsink[i]);
578 gst_bin_add (bin, stream->appsrc[i]);
579 gst_app_sink_set_callbacks (GST_APP_SINK_CAST (stream->appsink[i]),
580 &sink_cb, stream, NULL);
583 /* hook up the stream to the RTP session elements. */
584 name = g_strdup_printf ("send_rtp_sink_%u", idx);
585 stream->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
587 name = g_strdup_printf ("send_rtp_src_%u", idx);
588 stream->send_rtp_src = gst_element_get_static_pad (rtpbin, name);
590 name = g_strdup_printf ("send_rtcp_src_%u", idx);
591 stream->send_rtcp_src = gst_element_get_request_pad (rtpbin, name);
593 name = g_strdup_printf ("recv_rtcp_sink_%u", idx);
594 stream->recv_rtcp_sink = gst_element_get_request_pad (rtpbin, name);
596 name = g_strdup_printf ("recv_rtp_sink_%u", idx);
597 stream->recv_rtp_sink = gst_element_get_request_pad (rtpbin, name);
599 /* get the session */
600 g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &stream->session);
602 g_signal_connect (stream->session, "on-new-ssrc", (GCallback) on_new_ssrc,
604 g_signal_connect (stream->session, "on-ssrc-sdes", (GCallback) on_ssrc_sdes,
606 g_signal_connect (stream->session, "on-ssrc-active",
607 (GCallback) on_ssrc_active, stream);
608 g_signal_connect (stream->session, "on-bye-ssrc", (GCallback) on_bye_ssrc,
610 g_signal_connect (stream->session, "on-bye-timeout",
611 (GCallback) on_bye_timeout, stream);
612 g_signal_connect (stream->session, "on-timeout", (GCallback) on_timeout,
615 /* link the RTP pad to the session manager */
616 ret = gst_pad_link (stream->srcpad, stream->send_rtp_sink);
617 if (ret != GST_PAD_LINK_OK)
620 /* make tee for RTP and link to stream */
621 stream->tee[0] = gst_element_factory_make ("tee", NULL);
622 gst_bin_add (bin, stream->tee[0]);
624 pad = gst_element_get_static_pad (stream->tee[0], "sink");
625 gst_pad_link (stream->send_rtp_src, pad);
626 gst_object_unref (pad);
628 /* link RTP sink, we're pretty sure this will work. */
629 teepad = gst_element_get_request_pad (stream->tee[0], "src_%u");
630 pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
631 gst_pad_link (teepad, pad);
632 gst_object_unref (pad);
633 gst_object_unref (teepad);
635 teepad = gst_element_get_request_pad (stream->tee[0], "src_%u");
636 pad = gst_element_get_static_pad (stream->appqueue[0], "sink");
637 gst_pad_link (teepad, pad);
638 gst_object_unref (pad);
639 gst_object_unref (teepad);
641 queuepad = gst_element_get_static_pad (stream->appqueue[0], "src");
642 pad = gst_element_get_static_pad (stream->appsink[0], "sink");
643 gst_pad_link (queuepad, pad);
644 gst_object_unref (pad);
645 gst_object_unref (queuepad);
647 /* make tee for RTCP */
648 stream->tee[1] = gst_element_factory_make ("tee", NULL);
649 gst_bin_add (bin, stream->tee[1]);
651 pad = gst_element_get_static_pad (stream->tee[1], "sink");
652 gst_pad_link (stream->send_rtcp_src, pad);
653 gst_object_unref (pad);
655 /* link RTCP elements */
656 teepad = gst_element_get_request_pad (stream->tee[1], "src_%u");
657 pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
658 gst_pad_link (teepad, pad);
659 gst_object_unref (pad);
660 gst_object_unref (teepad);
662 teepad = gst_element_get_request_pad (stream->tee[1], "src_%u");
663 pad = gst_element_get_static_pad (stream->appqueue[1], "sink");
664 gst_pad_link (teepad, pad);
665 gst_object_unref (pad);
666 gst_object_unref (teepad);
668 queuepad = gst_element_get_static_pad (stream->appqueue[1], "src");
669 pad = gst_element_get_static_pad (stream->appsink[1], "sink");
670 gst_pad_link (queuepad, pad);
671 gst_object_unref (pad);
672 gst_object_unref (queuepad);
674 /* make selector for the RTP receivers */
675 stream->selector[0] = gst_element_factory_make ("funnel", NULL);
676 gst_bin_add (bin, stream->selector[0]);
678 pad = gst_element_get_static_pad (stream->selector[0], "src");
679 gst_pad_link (pad, stream->recv_rtp_sink);
680 gst_object_unref (pad);
682 selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u");
683 pad = gst_element_get_static_pad (stream->udpsrc[0], "src");
684 gst_pad_link (pad, selpad);
685 gst_object_unref (pad);
686 gst_object_unref (selpad);
687 selpad = gst_element_get_request_pad (stream->selector[0], "sink_%u");
688 pad = gst_element_get_static_pad (stream->appsrc[0], "src");
689 gst_pad_link (pad, selpad);
690 gst_object_unref (pad);
691 gst_object_unref (selpad);
693 /* make selector for the RTCP receivers */
694 stream->selector[1] = gst_element_factory_make ("funnel", NULL);
695 gst_bin_add (bin, stream->selector[1]);
697 pad = gst_element_get_static_pad (stream->selector[1], "src");
698 gst_pad_link (pad, stream->recv_rtcp_sink);
699 gst_object_unref (pad);
701 selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u");
702 pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
703 gst_pad_link (pad, selpad);
704 gst_object_unref (pad);
705 gst_object_unref (selpad);
707 selpad = gst_element_get_request_pad (stream->selector[1], "sink_%u");
708 pad = gst_element_get_static_pad (stream->appsrc[1], "src");
709 gst_pad_link (pad, selpad);
710 gst_object_unref (pad);
711 gst_object_unref (selpad);
713 /* we set and keep these to playing so that they don't cause NO_PREROLL return
715 gst_element_set_state (stream->udpsrc[0], GST_STATE_PLAYING);
716 gst_element_set_state (stream->udpsrc[1], GST_STATE_PLAYING);
717 gst_element_set_locked_state (stream->udpsrc[0], TRUE);
718 gst_element_set_locked_state (stream->udpsrc[1], TRUE);
720 /* be notified of caps changes */
721 stream->caps_sig = g_signal_connect (stream->send_rtp_sink, "notify::caps",
722 (GCallback) caps_notify, stream);
724 stream->is_joined = TRUE;
731 GST_WARNING ("failed to allocate ports %d", idx);
736 GST_WARNING ("failed to link stream %d", idx);
742 * gst_rtsp_stream_leave_bin:
743 * @stream: a #GstRTSPStream
745 * @rtpbin: a rtpbin #GstElement
747 * Remove the elements of @stream from the bin
749 * Return: %TRUE on success.
752 gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
757 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
758 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
759 g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
761 if (!stream->is_joined)
764 GST_INFO ("stream %p leaving bin", stream);
766 gst_pad_unlink (stream->srcpad, stream->send_rtp_sink);
768 g_signal_handler_disconnect (stream->send_rtp_sink, stream->caps_sig);
770 /* FIXME not entirely the opposite of join_bin */
771 for (i = 0; i < 2; i++) {
772 gst_bin_remove (bin, stream->udpsrc[i]);
773 gst_bin_remove (bin, stream->udpsink[i]);
774 gst_bin_remove (bin, stream->appsrc[i]);
775 gst_bin_remove (bin, stream->appsink[i]);
776 gst_bin_remove (bin, stream->appqueue[i]);
777 gst_bin_remove (bin, stream->tee[i]);
778 gst_bin_remove (bin, stream->selector[i]);
780 stream->is_joined = FALSE;
786 * gst_rtsp_stream_get_rtpinfo:
787 * @stream: a #GstRTSPStream
788 * @rtptime: result RTP timestamp
789 * @seq: result RTP seqnum
791 * Retrieve the current rtptime and seq. This is used to
792 * construct a RTPInfo reply header.
794 * Returns: %TRUE when rtptime and seq could be determined.
797 gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
798 guint * rtptime, guint * seq)
800 GObjectClass *payobjclass;
802 payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
804 if (!g_object_class_find_property (payobjclass, "seqnum") ||
805 !g_object_class_find_property (payobjclass, "timestamp"))
808 g_object_get (stream->payloader, "seqnum", seq, "timestamp", rtptime, NULL);
814 * gst_rtsp_stream_recv_rtp:
815 * @stream: a #GstRTSPStream
816 * @buffer: (transfer full): a #GstBuffer
818 * Handle an RTP buffer for the stream. This method is usually called when a
819 * message has been received from a client using the TCP transport.
821 * This function takes ownership of @buffer.
823 * Returns: a GstFlowReturn.
826 gst_rtsp_stream_recv_rtp (GstRTSPStream * stream, GstBuffer * buffer)
830 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[0]), buffer);
836 * gst_rtsp_stream_recv_rtcp:
837 * @stream: a #GstRTSPStream
838 * @buffer: (transfer full): a #GstBuffer
840 * Handle an RTCP buffer for the stream. This method is usually called when a
841 * message has been received from a client using the TCP transport.
843 * This function takes ownership of @buffer.
845 * Returns: a GstFlowReturn.
848 gst_rtsp_stream_recv_rtcp (GstRTSPStream * stream, GstBuffer * buffer)
852 ret = gst_app_src_push_buffer (GST_APP_SRC_CAST (stream->appsrc[1]), buffer);
858 update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
861 GstRTSPTransport *tr;
866 tr = trans->transport;
868 switch (tr->lower_transport) {
869 case GST_RTSP_LOWER_TRANS_UDP:
870 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
876 dest = tr->destination;
877 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
882 min = tr->client_port.min;
883 max = tr->client_port.max;
886 if (add && !trans->active) {
887 GST_INFO ("adding %s:%d-%d", dest, min, max);
888 g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
889 g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
891 GST_INFO ("setting ttl-mc %d", ttl);
892 g_object_set (G_OBJECT (stream->udpsink[0]), "ttl-mc", ttl, NULL);
893 g_object_set (G_OBJECT (stream->udpsink[1]), "ttl-mc", ttl, NULL);
895 stream->transports = g_list_prepend (stream->transports, trans);
896 trans->active = TRUE;
898 } else if (trans->active) {
899 GST_INFO ("removing %s:%d-%d", dest, min, max);
900 g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
901 g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
902 stream->transports = g_list_remove (stream->transports, trans);
903 trans->active = FALSE;
908 case GST_RTSP_LOWER_TRANS_TCP:
909 if (add && !trans->active) {
910 GST_INFO ("adding TCP %s", tr->destination);
911 stream->transports = g_list_prepend (stream->transports, trans);
912 trans->active = TRUE;
914 } else if (trans->active) {
915 GST_INFO ("removing TCP %s", tr->destination);
916 stream->transports = g_list_remove (stream->transports, trans);
917 trans->active = FALSE;
922 GST_INFO ("Unknown transport %d", tr->lower_transport);
930 * gst_rtsp_stream_add_transport:
931 * @stream: a #GstRTSPStream
932 * @trans: a #GstRTSPStreamTransport
934 * Add the transport in @trans to @stream. The media of @stream will
935 * then also be send to the values configured in @trans.
937 * @trans must contain a valid #GstRTSPTransport.
939 * Returns: %TRUE if @trans was added
942 gst_rtsp_stream_add_transport (GstRTSPStream * stream,
943 GstRTSPStreamTransport * trans)
945 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
946 g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
947 g_return_val_if_fail (trans->transport != NULL, FALSE);
949 return update_transport (stream, trans, TRUE);
953 * gst_rtsp_stream_remove_transport:
954 * @stream: a #GstRTSPStream
955 * @trans: a #GstRTSPStreamTransport
957 * Remove the transport in @trans from @stream. The media of @stream will
958 * not be sent to the values configured in @trans.
960 * Returns: %TRUE if @trans was removed
963 gst_rtsp_stream_remove_transport (GstRTSPStream * stream,
964 GstRTSPStreamTransport * trans)
966 g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
967 g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
968 g_return_val_if_fail (trans->transport != NULL, FALSE);
970 return update_transport (stream, trans, FALSE);