rtpmanagerbad: add RTP streaming elements
[platform/upstream/gstreamer.git] / gst / rtp / gstrtpsrc.c
1 /* GStreamer
2  * Copyright (C) <2018> Marc Leeman <marc.leeman@gmail.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * SECTION: gstrtpsrc
22  * @title: GstRtpSrc
23  * @short description: element with Uri interface to get RTP data from
24  * the network.
25  *
26  * RTP (RFC 3550) is a protocol to stream media over the network while
27  * retaining the timing information and providing enough information to
28  * reconstruct the correct timing domain by the receiver.
29  *
30  * The RTP data port should be even, while the RTCP port should be
31  * odd. The URI that is entered defines the data port, the RTCP port will
32  * be allocated to the next port.
33  *
34  * This element hooks up the correct sockets to support both RTP as the
35  * accompanying RTCP layer.
36  *
37  * This Bin handles taking in of data from the network and provides the
38  * RTP payloaded data.
39  *
40  * This element also implements the URI scheme `rtp://` allowing to render
41  * RTP streams in GStreamer based media players. The RTP URI handler also
42  * allows setting properties through the URI query.
43  */
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #include <gst/net/net.h>
49 #include <gst/rtp/gstrtppayloads.h>
50
51 #include "gstrtpsrc.h"
52 #include "gstrtp-utils.h"
53
54 GST_DEBUG_CATEGORY_STATIC (gst_rtp_src_debug);
55 #define GST_CAT_DEFAULT gst_rtp_src_debug
56
57 #define DEFAULT_PROP_TTL              64
58 #define DEFAULT_PROP_TTL_MC           1
59 #define DEFAULT_PROP_ENCODING_NAME    NULL
60 #define DEFAULT_PROP_LATENCY          200
61
62 #define DEFAULT_PROP_URI              "rtp://0.0.0.0:5004"
63
64 enum
65 {
66   PROP_0,
67
68   PROP_URI,
69   PROP_TTL,
70   PROP_TTL_MC,
71   PROP_ENCODING_NAME,
72   PROP_LATENCY,
73
74   PROP_LAST
75 };
76
77 static void gst_rtp_src_uri_handler_init (gpointer g_iface,
78     gpointer iface_data);
79
80 #define gst_rtp_src_parent_class parent_class
81 G_DEFINE_TYPE_WITH_CODE (GstRtpSrc, gst_rtp_src, GST_TYPE_BIN,
82     G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_rtp_src_uri_handler_init);
83     GST_DEBUG_CATEGORY_INIT (gst_rtp_src_debug, "rtpsrc", 0, "RTP Source"));
84
85 #define GST_RTP_SRC_GET_LOCK(obj) (&((GstRtpSrc*)(obj))->lock)
86 #define GST_RTP_SRC_LOCK(obj) (g_mutex_lock (GST_RTP_SRC_GET_LOCK(obj)))
87 #define GST_RTP_SRC_UNLOCK(obj) (g_mutex_unlock (GST_RTP_SRC_GET_LOCK(obj)))
88
89 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
90     GST_PAD_SRC,
91     GST_PAD_SOMETIMES,
92     GST_STATIC_CAPS ("application/x-rtp"));
93
94 static GstStateChangeReturn
95 gst_rtp_src_change_state (GstElement * element, GstStateChange transition);
96
97 /**
98  * gst_rtp_src_rtpbin_erquest_pt_map_cb:
99  * @self: The current #GstRtpSrc object
100  *
101  * #GstRtpBin callback to map a pt on RTP caps.
102  *
103  * Returns: (transfer none): the guess on the RTP caps based on the PT
104  * and caps.
105  */
106 static GstCaps *
107 gst_rtp_src_rtpbin_request_pt_map_cb (GstElement * rtpbin, guint session_id,
108     guint pt, gpointer data)
109 {
110   GstRtpSrc *self = GST_RTP_SRC (data);
111   const GstRTPPayloadInfo *p = NULL;
112
113   GST_DEBUG_OBJECT (self,
114       "Requesting caps for session-id 0x%x and pt %u.", session_id, pt);
115
116   /* the encoding-name has more relevant information */
117   if (self->encoding_name != NULL) {
118     /* Unfortunately, the media needs to be passed in the function. Since
119      * it is not known, try for video if video not found. */
120     p = gst_rtp_payload_info_for_name ("video", self->encoding_name);
121     if (p == NULL)
122       p = gst_rtp_payload_info_for_name ("audio", self->encoding_name);
123
124   }
125
126   /* Static payload types, this is a simple lookup */
127   if (!GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) {
128     p = gst_rtp_payload_info_for_pt (pt);
129   }
130
131   if (p != NULL) {
132     GstCaps *ret = gst_caps_new_simple ("application/x-rtp",
133         "encoding-name", G_TYPE_STRING, p->encoding_name,
134         "clock-rate", G_TYPE_INT, p->clock_rate,
135         "media", G_TYPE_STRING, p->media, NULL);
136
137     GST_DEBUG_OBJECT (self, "Decided on caps %" GST_PTR_FORMAT, ret);
138
139     return ret;
140   }
141
142   GST_DEBUG_OBJECT (self, "Could not determine caps based on pt and"
143       " the encoding-name was not set.");
144   return NULL;
145 }
146
147 static void
148 gst_rtp_src_set_property (GObject * object, guint prop_id,
149     const GValue * value, GParamSpec * pspec)
150 {
151   GstRtpSrc *self = GST_RTP_SRC (object);
152   GstCaps *caps;
153
154   switch (prop_id) {
155     case PROP_URI:{
156       GstUri *uri = NULL;
157
158       GST_RTP_SRC_LOCK (object);
159       uri = gst_uri_from_string (g_value_get_string (value));
160       if (uri == NULL)
161         break;
162
163       if (self->uri)
164         gst_uri_unref (self->uri);
165       self->uri = uri;
166       if (gst_uri_get_port (self->uri) % 2)
167         GST_WARNING_OBJECT (self,
168             "Port %u is not even, this is not standard (see RFC 3550).",
169             gst_uri_get_port (self->uri));
170       gst_rtp_utils_set_properties_from_uri_query (G_OBJECT (self), self->uri);
171       GST_RTP_SRC_UNLOCK (object);
172       break;
173     }
174     case PROP_TTL:
175       self->ttl = g_value_get_int (value);
176       break;
177     case PROP_TTL_MC:
178       self->ttl_mc = g_value_get_int (value);
179       break;
180     case PROP_ENCODING_NAME:
181       g_free (self->encoding_name);
182       self->encoding_name = g_value_dup_string (value);
183       if (self->rtp_src) {
184         caps = gst_rtp_src_rtpbin_request_pt_map_cb (NULL, 0, 96, self);
185         g_object_set (G_OBJECT (self->rtp_src), "caps", caps, NULL);
186         gst_caps_unref (caps);
187       }
188       break;
189     case PROP_LATENCY:
190       self->latency = g_value_get_uint (value);
191       break;
192     default:
193       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
194       break;
195   }
196 }
197
198 static void
199 gst_rtp_src_get_property (GObject * object, guint prop_id,
200     GValue * value, GParamSpec * pspec)
201 {
202   GstRtpSrc *self = GST_RTP_SRC (object);
203
204   switch (prop_id) {
205     case PROP_URI:
206       GST_RTP_SRC_LOCK (object);
207       if (self->uri)
208         g_value_take_string (value, gst_uri_to_string (self->uri));
209       else
210         g_value_set_string (value, NULL);
211       GST_RTP_SRC_UNLOCK (object);
212       break;
213     case PROP_TTL:
214       g_value_set_int (value, self->ttl);
215       break;
216     case PROP_TTL_MC:
217       g_value_set_int (value, self->ttl_mc);
218       break;
219     case PROP_ENCODING_NAME:
220       g_value_set_string (value, self->encoding_name);
221       break;
222     case PROP_LATENCY:
223       g_value_set_uint (value, self->latency);
224       break;
225     default:
226       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
227       break;
228   }
229 }
230
231 static void
232 gst_rtp_src_finalize (GObject * gobject)
233 {
234   GstRtpSrc *self = GST_RTP_SRC (gobject);
235
236   if (self->uri)
237     gst_uri_unref (self->uri);
238   g_free (self->encoding_name);
239
240   g_mutex_clear (&self->lock);
241   G_OBJECT_CLASS (parent_class)->finalize (gobject);
242 }
243
244 static void
245 gst_rtp_src_class_init (GstRtpSrcClass * klass)
246 {
247   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
248   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
249
250   gobject_class->set_property = gst_rtp_src_set_property;
251   gobject_class->get_property = gst_rtp_src_get_property;
252   gobject_class->finalize = gst_rtp_src_finalize;
253   gstelement_class->change_state = gst_rtp_src_change_state;
254
255   /**
256    * GstRtpSrc:uri:
257    *
258    * uri to an RTP from. All GStreamer parameters can be
259    * encoded in the URI, this URI format is RFC compliant.
260    */
261   g_object_class_install_property (gobject_class, PROP_URI,
262       g_param_spec_string ("uri", "URI",
263           "URI in the form of rtp://host:port?query", DEFAULT_PROP_URI,
264           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
265
266   /**
267    * GstRtpSrc:ttl:
268    *
269    * Set the unicast TTL parameter. In RTP this of importance for RTCP.
270    */
271   g_object_class_install_property (gobject_class, PROP_TTL,
272       g_param_spec_int ("ttl", "Unicast TTL",
273           "Used for setting the unicast TTL parameter",
274           0, 255, DEFAULT_PROP_TTL,
275           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276
277   /**
278    * GstRtpSrc:ttl-mc:
279    *
280    * Set the multicast TTL parameter. In RTP this of importance for RTCP.
281    */
282   g_object_class_install_property (gobject_class, PROP_TTL_MC,
283       g_param_spec_int ("ttl-mc", "Multicast TTL",
284           "Used for setting the multicast TTL parameter", 0, 255,
285           DEFAULT_PROP_TTL_MC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286
287   /**
288    * GstRtpSrc:encoding-name:
289    *
290    * Set the encoding name of the stream to use. This is a short-hand for
291    * the full caps and maps typically to the encoding-name in the RTP caps.
292    */
293   g_object_class_install_property (gobject_class, PROP_ENCODING_NAME,
294       g_param_spec_string ("encoding-name", "Caps encoding name",
295           "Encoding name use to determine caps parameters",
296           DEFAULT_PROP_ENCODING_NAME,
297           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
298
299   /**
300    * GstRtpSrc:latency:
301    *
302    * Set the size of the latency buffer in the
303    * GstRtpBin/GstRtpJitterBuffer to compensate for network jitter.
304    */
305   g_object_class_install_property (gobject_class, PROP_LATENCY,
306       g_param_spec_uint ("latency", "Buffer latency in ms",
307           "Default amount of ms to buffer in the jitterbuffers", 0,
308           G_MAXUINT, DEFAULT_PROP_LATENCY,
309           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310
311   gst_element_class_add_pad_template (gstelement_class,
312       gst_static_pad_template_get (&src_template));
313
314   gst_element_class_set_static_metadata (gstelement_class,
315       "RTP Source element",
316       "Generic/Bin/Src",
317       "Simple RTP src", "Marc Leeman <marc.leeman@gmail.com>");
318 }
319
320 static void
321 gst_rtp_src_rtpbin_pad_added_cb (GstElement * element, GstPad * pad,
322     gpointer data)
323 {
324   GstRtpSrc *self = GST_RTP_SRC (data);
325   GstCaps *caps = gst_pad_query_caps (pad, NULL);
326   GstPad *upad;
327   gchar name[48];
328
329   /* Expose RTP data pad only */
330   GST_INFO_OBJECT (self,
331       "Element %" GST_PTR_FORMAT " added pad %" GST_PTR_FORMAT "with caps %"
332       GST_PTR_FORMAT ".", element, pad, caps);
333
334   /* Sanity checks */
335   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
336     /* Sink pad, do not expose */
337     gst_caps_unref (caps);
338     return;
339   }
340
341   if (G_LIKELY (caps)) {
342     GstCaps *ref_caps = gst_caps_new_empty_simple ("application/x-rtcp");
343
344     if (gst_caps_can_intersect (caps, ref_caps)) {
345       /* SRC RTCP caps, do not expose */
346       gst_caps_unref (ref_caps);
347       gst_caps_unref (caps);
348
349       return;
350     }
351     gst_caps_unref (ref_caps);
352   } else {
353     GST_ERROR_OBJECT (self, "Pad with no caps detected.");
354     gst_caps_unref (caps);
355
356     return;
357   }
358   gst_caps_unref (caps);
359
360   GST_RTP_SRC_LOCK (self);
361   g_snprintf (name, 48, "src_%u", GST_ELEMENT (self)->numpads);
362   upad = gst_ghost_pad_new (name, pad);
363
364   gst_pad_set_active (upad, TRUE);
365   gst_element_add_pad (GST_ELEMENT (self), upad);
366
367   GST_RTP_SRC_UNLOCK (self);
368 }
369
370 static void
371 gst_rtp_src_rtpbin_pad_removed_cb (GstElement * element, GstPad * pad,
372     gpointer data)
373 {
374   GstRtpSrc *self = GST_RTP_SRC (data);
375   GST_INFO_OBJECT (self,
376       "Element %" GST_PTR_FORMAT " removed pad %" GST_PTR_FORMAT ".", element,
377       pad);
378 }
379
380 static void
381 gst_rtp_src_rtpbin_on_ssrc_collision_cb (GstElement * rtpbin, guint session_id,
382     guint ssrc, gpointer data)
383 {
384   GstRtpSrc *self = GST_RTP_SRC (data);
385
386   GST_INFO_OBJECT (self,
387       "Dectected an SSRC collision: session-id 0x%x, ssrc 0x%x.", session_id,
388       ssrc);
389 }
390
391 static void
392 gst_rtp_src_rtpbin_on_new_ssrc_cb (GstElement * rtpbin, guint session_id,
393     guint ssrc, gpointer data)
394 {
395   GstRtpSrc *self = GST_RTP_SRC (data);
396
397   GST_INFO_OBJECT (self, "Dectected a new SSRC: session-id 0x%x, ssrc 0x%x.",
398       session_id, ssrc);
399 }
400
401 static GstPadProbeReturn
402 gst_rtp_src_on_recv_rtcp (GstPad * pad, GstPadProbeInfo * info,
403     gpointer user_data)
404 {
405   GstRtpSrc *self = GST_RTP_SRC (user_data);
406   GstBuffer *buffer;
407   GstNetAddressMeta *meta;
408
409   if (info->type == GST_PAD_PROBE_TYPE_BUFFER_LIST) {
410     GstBufferList *buffer_list = info->data;
411     buffer = gst_buffer_list_get (buffer_list, 0);
412   } else {
413     buffer = info->data;
414   }
415
416   meta = gst_buffer_get_net_address_meta (buffer);
417
418   GST_OBJECT_LOCK (self);
419   g_clear_object (&self->rtcp_send_addr);
420   self->rtcp_send_addr = g_object_ref (meta->addr);
421   GST_OBJECT_UNLOCK (self);
422
423   return GST_PAD_PROBE_OK;
424 }
425
426 static inline void
427 gst_rtp_src_attach_net_address_meta (GstRtpSrc * self, GstBuffer * buffer)
428 {
429   GST_OBJECT_LOCK (self);
430   if (self->rtcp_send_addr)
431     gst_buffer_add_net_address_meta (buffer, self->rtcp_send_addr);
432   GST_OBJECT_UNLOCK (self);
433 }
434
435 static GstPadProbeReturn
436 gst_rtp_src_on_send_rtcp (GstPad * pad, GstPadProbeInfo * info,
437     gpointer user_data)
438 {
439   GstRtpSrc *self = GST_RTP_SRC (user_data);
440
441   if (info->type == GST_PAD_PROBE_TYPE_BUFFER_LIST) {
442     GstBufferList *buffer_list = info->data;
443     GstBuffer *buffer;
444     gint i;
445
446     info->data = buffer_list = gst_buffer_list_make_writable (buffer_list);
447     for (i = 0; i < gst_buffer_list_length (buffer_list); i++) {
448       buffer = gst_buffer_list_get (buffer_list, i);
449       gst_rtp_src_attach_net_address_meta (self, buffer);
450     }
451   } else {
452     GstBuffer *buffer = info->data;
453     info->data = buffer = gst_buffer_make_writable (buffer);
454     gst_rtp_src_attach_net_address_meta (self, buffer);
455   }
456
457   return GST_PAD_PROBE_OK;
458 }
459
460 static gboolean
461 gst_rtp_src_setup_elements (GstRtpSrc * self)
462 {
463   GstPad *pad;
464   GSocket *socket;
465   GInetAddress *addr;
466   gchar name[48];
467   GstCaps *caps;
468   gchar *address;
469   guint rtcp_port;
470
471   /* Construct the RTP receiver pipeline.
472    *
473    * udpsrc -> [recv_rtp_sink_%u]  --------  [recv_rtp_src_%u_%u_%u]
474    *                              | rtpbin |
475    * udpsrc -> [recv_rtcp_sink_%u] --------  [send_rtcp_src_%u] -> udpsink
476    *
477    * This pipeline is fixed for now, note that optionally an FEC stream could
478    * be added later.
479    */
480
481   /* Should not be NULL */
482   g_return_val_if_fail (self->uri != NULL, FALSE);
483
484   self->rtpbin = gst_element_factory_make ("rtpbin", NULL);
485   if (self->rtpbin == NULL) {
486     GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
487         ("%s", "rtpbin element is not available"));
488     return FALSE;
489   }
490
491   self->rtp_src = gst_element_factory_make ("udpsrc", NULL);
492   if (self->rtp_src == NULL) {
493     GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
494         ("%s", "rtp_src element is not available"));
495     return FALSE;
496   }
497
498   self->rtcp_src = gst_element_factory_make ("udpsrc", NULL);
499   if (self->rtcp_src == NULL) {
500     GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
501         ("%s", "rtcp_src element is not available"));
502     return FALSE;
503   }
504
505   self->rtcp_sink = gst_element_factory_make ("dynudpsink", NULL);
506   if (self->rtcp_sink == NULL) {
507     GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
508         ("%s", "rtcp_sink element is not available"));
509     return FALSE;
510   }
511
512   /* Add rtpbin callbacks to monitor the operation of rtpbin */
513   g_signal_connect (self->rtpbin, "pad-added",
514       G_CALLBACK (gst_rtp_src_rtpbin_pad_added_cb), self);
515   g_signal_connect (self->rtpbin, "pad-removed",
516       G_CALLBACK (gst_rtp_src_rtpbin_pad_removed_cb), self);
517   g_signal_connect (self->rtpbin, "request-pt-map",
518       G_CALLBACK (gst_rtp_src_rtpbin_request_pt_map_cb), self);
519   g_signal_connect (self->rtpbin, "on-new-ssrc",
520       G_CALLBACK (gst_rtp_src_rtpbin_on_new_ssrc_cb), self);
521   g_signal_connect (self->rtpbin, "on-ssrc-collision",
522       G_CALLBACK (gst_rtp_src_rtpbin_on_ssrc_collision_cb), self);
523
524   g_object_set (self->rtpbin, "latency", self->latency, NULL);
525
526   /* Add elements as needed, since udpsrc/udpsink for RTCP share a socket,
527    * not all at the same moment */
528   gst_bin_add (GST_BIN (self), self->rtpbin);
529   gst_bin_add (GST_BIN (self), self->rtp_src);
530
531   g_object_set (self->rtp_src,
532       "address", gst_uri_get_host (self->uri),
533       "port", gst_uri_get_port (self->uri), NULL);
534
535   gst_bin_add (GST_BIN (self), self->rtcp_sink);
536
537   /* no need to set address if unicast */
538   caps = gst_caps_new_empty_simple ("application/x-rtcp");
539   g_object_set (self->rtcp_src,
540       "port", gst_uri_get_port (self->uri) + 1, "caps", caps, NULL);
541   gst_caps_unref (caps);
542
543   addr = g_inet_address_new_from_string (gst_uri_get_host (self->uri));
544   if (g_inet_address_get_is_multicast (addr)) {
545     g_object_set (self->rtcp_src, "address", gst_uri_get_host (self->uri),
546         NULL);
547   }
548   g_object_unref (addr);
549
550   g_object_set (self->rtcp_sink,
551       "host", gst_uri_get_host (self->uri),
552       "port", gst_uri_get_port (self->uri) + 1,
553       "ttl", self->ttl, "ttl-mc", self->ttl_mc,
554       /* Set false since we're reusing a socket */
555       "auto-multicast", FALSE, NULL);
556
557   gst_bin_add (GST_BIN (self), self->rtcp_src);
558
559   /* share the socket created by the source */
560   g_object_get (G_OBJECT (self->rtcp_src), "used-socket", &socket,
561       "address", &address, "port", &rtcp_port, NULL);
562
563   addr = g_inet_address_new_from_string (address);
564   g_free (address);
565
566   if (g_inet_address_get_is_multicast (addr)) {
567     /* mc-ttl is not supported by dynudpsink */
568     g_socket_set_multicast_ttl (socket, self->ttl_mc);
569     /* In multicast, send RTCP to the multicast group */
570     self->rtcp_send_addr = g_inet_socket_address_new (addr, rtcp_port);
571   } else {
572     /* In unicast, send RTCP to the detected sender address */
573     pad = gst_element_get_static_pad (self->rtcp_src, "src");
574     self->rtcp_recv_probe = gst_pad_add_probe (pad,
575         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
576         gst_rtp_src_on_recv_rtcp, self, NULL);
577     gst_object_unref (pad);
578   }
579   g_object_unref (addr);
580
581   pad = gst_element_get_static_pad (self->rtcp_sink, "sink");
582   self->rtcp_send_probe = gst_pad_add_probe (pad,
583       GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
584       gst_rtp_src_on_send_rtcp, self, NULL);
585   gst_object_unref (pad);
586
587   g_object_set (G_OBJECT (self->rtcp_sink), "socket", socket, NULL);
588
589   /* pads are all named */
590   g_snprintf (name, 48, "recv_rtp_sink_%u", GST_ELEMENT (self)->numpads);
591   gst_element_link_pads (self->rtp_src, "src", self->rtpbin, name);
592
593   g_snprintf (name, 48, "recv_rtcp_sink_%u", GST_ELEMENT (self)->numpads);
594   gst_element_link_pads (self->rtcp_src, "src", self->rtpbin, name);
595
596   gst_element_sync_state_with_parent (self->rtpbin);
597   gst_element_sync_state_with_parent (self->rtp_src);
598   gst_element_sync_state_with_parent (self->rtcp_sink);
599
600   g_snprintf (name, 48, "send_rtcp_src_%u", GST_ELEMENT (self)->numpads);
601   gst_element_link_pads (self->rtpbin, name, self->rtcp_sink, "sink");
602
603   gst_element_sync_state_with_parent (self->rtcp_src);
604
605   return TRUE;
606 }
607
608 static void
609 gst_rtp_src_stop (GstRtpSrc * self)
610 {
611   GstPad *pad;
612
613   if (self->rtcp_recv_probe) {
614     pad = gst_element_get_static_pad (self->rtcp_src, "src");
615     gst_pad_remove_probe (pad, self->rtcp_recv_probe);
616     self->rtcp_recv_probe = 0;
617     gst_object_unref (pad);
618   }
619
620   pad = gst_element_get_static_pad (self->rtcp_sink, "sink");
621   gst_pad_remove_probe (pad, self->rtcp_send_probe);
622   self->rtcp_send_probe = 0;
623   gst_object_unref (pad);
624 }
625
626 static GstStateChangeReturn
627 gst_rtp_src_change_state (GstElement * element, GstStateChange transition)
628 {
629   GstRtpSrc *self = GST_RTP_SRC (element);
630   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
631
632   GST_DEBUG_OBJECT (self, "Changing state: %s => %s",
633       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
634       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
635
636   switch (transition) {
637     case GST_STATE_CHANGE_NULL_TO_READY:
638       if (gst_rtp_src_setup_elements (self) == FALSE)
639         return GST_STATE_CHANGE_FAILURE;
640       break;
641     default:
642       break;
643   }
644
645   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
646   if (ret == GST_STATE_CHANGE_FAILURE)
647     return ret;
648
649   switch (transition) {
650     case GST_STATE_CHANGE_READY_TO_PAUSED:
651       ret = GST_STATE_CHANGE_NO_PREROLL;
652       break;
653     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
654       ret = GST_STATE_CHANGE_NO_PREROLL;
655       break;
656     case GST_STATE_CHANGE_READY_TO_NULL:
657       gst_rtp_src_stop (self);
658       break;
659     default:
660       break;
661   }
662
663   return ret;
664 }
665
666 static void
667 gst_rtp_src_init (GstRtpSrc * self)
668 {
669   self->rtpbin = NULL;
670   self->rtp_src = NULL;
671   self->rtcp_src = NULL;
672   self->rtcp_sink = NULL;
673
674   self->uri = gst_uri_from_string (DEFAULT_PROP_URI);
675   self->ttl = DEFAULT_PROP_TTL;
676   self->ttl_mc = DEFAULT_PROP_TTL_MC;
677   self->encoding_name = DEFAULT_PROP_ENCODING_NAME;
678   self->latency = DEFAULT_PROP_LATENCY;
679
680   GST_OBJECT_FLAG_SET (GST_OBJECT (self), GST_ELEMENT_FLAG_SOURCE);
681   gst_bin_set_suppressed_flags (GST_BIN (self),
682       GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
683
684   g_mutex_init (&self->lock);
685 }
686
687 static guint
688 gst_rtp_src_uri_get_type (GType type)
689 {
690   return GST_URI_SRC;
691 }
692
693 static const gchar *const *
694 gst_rtp_src_uri_get_protocols (GType type)
695 {
696   static const gchar *protocols[] = { (char *) "rtp", NULL };
697
698   return protocols;
699 }
700
701 static gchar *
702 gst_rtp_src_uri_get_uri (GstURIHandler * handler)
703 {
704   GstRtpSrc *self = (GstRtpSrc *) handler;
705
706   return gst_uri_to_string (self->uri);
707 }
708
709 static gboolean
710 gst_rtp_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
711     GError ** error)
712 {
713   GstRtpSrc *self = (GstRtpSrc *) handler;
714
715   g_object_set (G_OBJECT (self), "uri", uri, NULL);
716
717   return TRUE;
718 }
719
720 static void
721 gst_rtp_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
722 {
723   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
724
725   iface->get_type = gst_rtp_src_uri_get_type;
726   iface->get_protocols = gst_rtp_src_uri_get_protocols;
727   iface->get_uri = gst_rtp_src_uri_get_uri;
728   iface->set_uri = gst_rtp_src_uri_set_uri;
729 }
730
731 /* ex: set tabstop=2 shiftwidth=2 expandtab: */